A hardened Nginx web server configured to run unprivileged with the hardenedeu user (UID 10000), featuring security-hardened configurations, FIPS and optimized for containerized deployments.
Getting Started
To pull the image:
docker pull registry.hardened.eu/library/nginx-fips:latest
Example: Running FIPS-Compliant Nginx with Custom Configuration
The Hardened B.V. nginx-fips image runs unprivileged with the hardenedeu
user (UID 10000) for enhanced security. This FIPS-compliant variant uses FIPS-approved cryptographic algorithms and configurations, making it suitable for environments requiring Federal Information Processing Standards compliance.
Default Configuration
The image includes a hardened nginx configuration with the following default server block:
server {
listen 8080 default_server;
listen [::]:8080 default_server;
# Everything is a 404
location / {
return 404;
}
# You may need this to prevent return 404 recursion.
location = /404.html {
internal;
}
}
Running the Container
docker run -p 8080:8080 registry.hardened.eu/library/nginx-fips:latest
Adding Custom Virtual Hosts
To add your own virtual host configuration, create a custom Dockerfile:
FROM registry.hardened.eu/library/nginx-fips:latest
# Copy your custom nginx configuration
COPY my-site.conf /etc/nginx/http.d/
# Copy your website files
COPY website/ /usr/share/nginx/html/
# Ensure proper permissions for the hardenedeu user
RUN chown -R 10000:10000 /usr/share/nginx/html /etc/nginx/http.d/
FIPS Compliance Verification
To verify that the nginx environment is using FIPS-compliant OpenSSL and cryptographic algorithms:
# Check OpenSSL FIPS status
docker run --rm registry.hardened.eu/library/nginx-fips:latest openssl version -a
# Verify FIPS provider is loaded
docker run --rm registry.hardened.eu/library/nginx-fips:latest openssl list -providers
Expected output should indicate FIPS provider usage and reference the FIPS configuration file.
Security Hardening Features
The nginx-fips image includes several security enhancements:
nginx.conf.hardened
with security optimizationsVolume Mounts
For persistent configurations and logs:
docker run -p 8080:8080 \
-v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /path/to/sites:/etc/nginx/http.d:ro \
-v /path/to/html:/usr/share/nginx/html:ro \
registry.hardened.eu/library/nginx-fips:latest
Health Checks
The container is configured to respond to health checks on port 8080. You can verify the container is running:
curl -I http://localhost:8080
Expected response: HTTP/1.1 404 Not Found
Custom SSL/TLS Configuration with FIPS Compliance
For HTTPS support with FIPS-approved algorithms, mount your certificates and update the configuration. Note that the default configuration uses port 8080, but SSL/TLS typically uses port 8443:
server {
listen 8443 ssl;
server_name example.com;
http2 on;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# FIPS-compliant SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /usr/share/nginx/html;
index index.html;
}
More complex sample using the Mozilla SSL config generator (contact us for a reference implementation):
# https://ssl-config.mozilla.org, nginx intermediate
http {
server {
listen 8443 ssl;
listen [::]:8443 ssl;
http2 on;
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
}
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# see also ssl_session_ticket_key alternative to stateful session cache
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam "/path/to/dhparam";
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
# replace with the IP address of your resolver;
# async 'resolver' is important for proper operation of OCSP stapling
resolver 127.0.0.1;
}
Run with SSL/TLS:
docker run -p 8443:8443 \
-v /path/to/ssl:/etc/nginx/ssl:ro \
-v /path/to/sites:/etc/nginx/http.d:ro \
registry.hardened.eu/library/nginx-fips:latest
Verifying Image Signatures
All Hardened B.V. images are signed using cosign. You can verify the signature using the following steps:
Save the public key:
cat >hardened.pub <<EOL
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbxhUFlXkIIbDzdRAR9rc6kDPNb+k
J48lhqqlOMyiq3jkbKXNj2sEFMduFlNh63MrZA59PKf4TjS1AiCrvaFXNA==
-----END PUBLIC KEY-----
EOL
Verify the image signature:
cosign verify --key hardened.pub registry.hardened.eu/library/nginx-fips:latest
The verification will show the signature details and confirm the image’s authenticity.
To verify the SBOM, run the following command:
cosign verify-attestation --type spdxjson --key hardened.pub registry.hardened.eu/library/nginx-fips:latest
To download the SBOM, run the same command and decode it:
cosign verify-attestation --type spdxjson --key hardened.pub registry.hardened.eu/library/nginx-fips:latest | jq -r .payload | base64 -d | jq -r .predicate > nginx-fips-spdx.json
Trademarks
This software is packaged by Hardened B.V. All trademarks are property of their respective owners. Use of these images does not imply any affiliation or endorsement.