Skip to main content
CleanStart

Knowledge Hub

FIPS-Compliant Nginx: TLS Configuration and Cipher Suites

Running FIPS-Compliant Nginx

Nginx serves as a TLS termination point, handling encryption for applications. FIPS compliance requires that Nginx uses FIPS-validated cryptographic modules and only FIPS-approved ciphers.

Compiling Nginx with OpenSSL FIPS module and configuring secure TLS settings enables FIPS-compliant encryption.

Prerequisites

OpenSSL 3.0+ FIPS module (CMVP #4949), Nginx 1.24+ (good OpenSSL 3.x support), and FIPS-enabled Linux system.

Compiling Nginx with FIPS OpenSSL

Build Nginx Against FIPS OpenSSL

# Install FIPS OpenSSL and build toolssudo apt-get update && apt-get install -y \  libssl3-fips \  openssl-fips \  build-essential \  libpcre3-dev \  zlib1g-dev # Download Nginx sourcecd /tmpwget http://nginx.org/download/nginx-1.26.1.tar.gztar xzf nginx-1.26.1.tar.gzcd nginx-1.26.1 # Configure with FIPS OpenSSL./configure \  --prefix=/etc/nginx \  --sbin-path=/usr/sbin/nginx \  --modules-path=/usr/lib64/nginx/modules \  --with-http_ssl_module \  --with-openssl=/usr/lib/fips \  --with-openssl-opt="fips shared" \  --with-http_gzip_static_module \  --with-http_v2_module # Build and installmakesudo make install # Verify FIPS modulenginx -vldd /usr/sbin/nginx | grep ssl# libssl.so => /usr/lib/fips/libssl.so

Docker: Nginx with FIPS

# Dockerfile: Nginx with FIPS OpenSSL FROM ubuntu:24.04-fips # Install build dependencies and FIPS OpenSSLRUN apt-get update && apt-get install -y \  build-essential \  libpcre3-dev \  zlib1g-dev \  libssl3-fips \  openssl-fips # Download and build Nginx with FIPSRUN cd /tmp && \  wget http://nginx.org/download/nginx-1.26.1.tar.gz && \  tar xzf nginx-1.26.1.tar.gz && \  cd nginx-1.26.1 && \  ./configure \    --prefix=/etc/nginx \    --sbin-path=/usr/sbin/nginx \    --with-http_ssl_module \    --with-openssl=/usr/lib/fips \    --with-openssl-opt="fips shared" \    --with-http_v2_module && \  make && make install # Verify FIPSRUN nginx -v 2>&1 | grep -i nginx && \  ldd /usr/sbin/nginx | grep fips EXPOSE 443 80CMD ["nginx", "-g", "daemon off;"]

FIPS TLS Configuration

Generate FIPS-Compliant Certificates

#!/bin/bash# generate-nginx-certs.sh # Generate 2048-bit RSA key (FIPS minimum)openssl genrsa -out private.key 2048 # Generate certificate signing requestopenssl req -new \  -key private.key \  -out server.csr \  -subj "/CN=example.com/O=Company/C=US" # Self-sign with SHA-256 (FIPS-approved)openssl x509 -req \  -in server.csr \  -signkey private.key \  -out server.crt \  -days 365 \  -sha256 # Create combined PEM for some clientscat server.crt private.key > server.pemchmod 600 private.key server.pem # Move to Nginx directorysudo mv server.crt server.pem /etc/nginx/certs/sudo chown nginx:nginx /etc/nginx/certs/*

Nginx Configuration with FIPS TLS

# /etc/nginx/nginx.conf user nginx;worker_processes auto;error_log /var/log/nginx/error.log warn; events {    worker_connections 1024;} http {    # HTTPS server    server {        listen 443 ssl http2;        listen [::]:443 ssl http2;        server_name example.com www.example.com;         # FIPS-compliant certificates        ssl_certificate /etc/nginx/certs/server.crt;        ssl_certificate_key /etc/nginx/certs/private.key;         # FIPS TLS versions only        ssl_protocols TLSv1.2 TLSv1.3;         # FIPS-approved cipher suites        ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256';         # Cipher ordering        ssl_prefer_server_ciphers on;         # Session configuration        ssl_session_cache shared:SSL:10m;        ssl_session_timeout 10m;        ssl_session_tickets off;         # HSTS (force TLS)        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;         # Other security headers        add_header X-Frame-Options "SAMEORIGIN" always;        add_header X-Content-Type-Options "nosniff" always;        add_header X-XSS-Protection "1; mode=block" always;         # Application location        location / {            proxy_pass http://localhost:8080;            proxy_set_header Host $host;            proxy_set_header X-Real-IP $remote_addr;            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;            proxy_set_header X-Forwarded-Proto $scheme;        }    }     # HTTP to HTTPS redirect    server {        listen 80;        listen [::]:80;        server_name example.com www.example.com;         return 301 https://$server_name$request_uri;    }}

Cipher Suites Breakdown

All configured ciphers are FIPS-approved. ECDHE-RSA-AES256-GCM-SHA384 uses Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) for key exchange, RSA for authentication, 256-bit AES encryption, Galois/Counter Mode (GCM) for authenticated encryption, and SHA384 as the hash function for the pseudo-random function (PRF).

ECDHE-RSA-AES128-GCM-SHA256 follows the same structure but uses 128-bit AES and 256-bit SHA2 hashing.

DHE-RSA-AES256-GCM-SHA384 substitutes Diffie-Hellman Ephemeral (DHE) as an alternative to ECDHE for key exchange while maintaining the same encryption and authentication approach.

All configured ciphers provide forward secrecy through ephemeral keys, authenticated encryption through GCM mode, and rely exclusively on FIPS-approved algorithms.

Client Certificate Authentication (Optional)

# /etc/nginx/nginx.conf - Client certificate auth server {    listen 443 ssl http2;    server_name example.com;     ssl_certificate /etc/nginx/certs/server.crt;    ssl_certificate_key /etc/nginx/certs/private.key;     # Client certificate verification    ssl_client_certificate /etc/nginx/certs/ca.crt;    ssl_verify_client on;    ssl_verify_depth 2;     location / {        proxy_pass http://localhost:8080;        # Pass client cert info        proxy_set_header SSL-Client-Cert $ssl_client_cert;        proxy_set_header SSL-Client-Verify $ssl_client_verify;    }}

FIPS Verification

Verify Nginx Uses FIPS OpenSSL

# Check Nginx version and OpenSSLnginx -v# Output: nginx/1.26.1 # Verify TLS modulesnginx -V 2>&1 | grep ssl# Output: --with-http_ssl_module # Check OpenSSL linkageldd /usr/sbin/nginx | grep libssl# libssl.so.3 => /usr/lib/fips/libssl.so.3 (FIPS) # Verify FIPS module is activeopenssl version# OpenSSL 3.0.10 (FIPS module 3.0.10 - CMVP Validated)

Test TLS Configuration

# Test SSL/TLS configurationopenssl s_client \  -connect example.com:443 \  -tls1_2 # Output should show:# subject=CN = example.com# issuer=... (certificate authority)# Protocol: TLSv1.2# Cipher: ECDHE-RSA-AES256-GCM-SHA384 (or similar FIPS cipher)

Nginx SSL Test

# Use online SSL test (Qualys)curl "https://api.ssllabs.com/api/v3/analyze?host=example.com" # Or local testingopenssl s_client -connect example.com:443 -tls1_3# Should successfully handshake with TLS 1.3

Automated FIPS Verification

# CleanStart FIPS verificationcleanimg-init --fips-verifier --image my-nginx:latest # Output:# Nginx is linked against FIPS OpenSSL# TLS 1.2/1.3 is configured# Only FIPS-approved ciphers are enabled# No deprecated algorithms detected (RC4, DES, etc.)# HSTS is enabled for production# Perfect Forward Secrecy (PFS) is enabled# FIPS compliance verified

Performance Optimization

Hardware Acceleration

# Use hardware crypto acceleration (if available)ssl_engine openssl;  # OpenSSL 3.x auto-detects hardware

Session Caching

# Shared memory cache (10 MB, 10 minute timeout)ssl_session_cache shared:SSL:10m;ssl_session_timeout 10m; # Disable session tickets (more secure but less performant)ssl_session_tickets off;

Common Configuration Issues

Issue: Old TLS Versions Enabled

# BAD: Allows deprecated TLSssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; # GOOD: FIPS-approved onlyssl_protocols TLSv1.2 TLSv1.3;

Issue: Non-FIPS Ciphers

# BAD: Includes non-FIPS ciphersssl_ciphers 'ALL:!aNULL'; # GOOD: Only FIPS-approvedssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:...';

Issue: Weak Key Size

# BAD: 1024-bit RSAopenssl genrsa -out key.pem 1024 # GOOD: 2048-bit RSA (FIPS minimum)openssl genrsa -out key.pem 2048 # Better: 4096-bit for extended securityopenssl genrsa -out key.pem 4096

Monitoring

Check TLS Handshake Success

# Monitor handshakestail -f /var/log/nginx/access.log | grep "SSL" # Check error logtail -f /var/log/nginx/error.log | grep "ssl"

Performance Metrics

# CPU usage (TLS is CPU-intensive)top -p $(pgrep nginx) # Connection statsss -s | grep TCP

Compliance Mapping

Requirement

Implementation

FIPS 140-3

OpenSSL 3.0 FIPS module #4949

NIST 800-171 SC-13

TLS 1.2/1.3, RSA-2048, AES-256-GCM

PCI DSS 4.1

Strong encryption in transit

HIPAA § 164.312(a)(2)(i)

FIPS-approved encryption

SOC 2 CC6.2

Cryptographic controls

See Also

FIPS Overview: fips-140-overview.md — FIPS principles, FIPS PostgreSQL: fips-postgresql.md — Database TLS patterns, and FIPS Kafka: fips-kafka.md — Message broker TLS.