đź“… Updated: June 10, 2026 (Originally published: January 21, 2026)
nginx tls 1.3 correctly is essential for achieving an A+ rating on SSL Labs while maximizing both security and performance. This comprehensive guide walks you through every step of hardening your NGINX TLS configuration, from basic setup to advanced optimizations.
Why TLS 1.3 Matters for Your NGINX Server
TLS 1.3 isn’t just an incremental update—it’s a fundamental improvement in how encrypted connections work. Here’s what makes it essential:
Faster handshakes: TLS 1.3 reduces the handshake from two round-trips to just one, improving Time to First Byte (TTFB)
Stronger security: Removed support for legacy algorithms like RSA key exchange, RC4, SHA-1, and CBC mode ciphers
Forward secrecy by default: Every connection uses ephemeral keys, so compromising your private key doesn’t expose past traffic
Simplified cipher suites: Only five secure cipher suites, eliminating configuration mistakes
Modern browsers have supported TLS 1.3 since 2018, and there’s no reason to use older protocols unless you need compatibility with ancient clients.
Prerequisites
Before configuring nginx tls 1.3 hardening, ensure your system meets these requirements:
For most production servers, the Intermediate configuration provides the best balance. Use Modern only when you’re certain all your clients support TLS 1.3.
Step 1: Create the SSL Hardening Configuration
Create a dedicated configuration file for your TLS settings. This keeps your SSL configuration modular and easy to maintain.
Modern Configuration (TLS 1.3 Only)
For maximum security when you don’t need legacy client support:
# /etc/nginx/conf.d/ssl-hardening.conf
# Mozilla Modern Configuration - TLS 1.3 Only
ssl_protocols TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_prefer_server_ciphers off;
# OCSP Stapling (for CAs that support it - see note below)
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.53 valid=300s;
resolver_timeout 5s;
With TLS 1.3, you don’t need to specify ssl_ciphers because the protocol only supports secure AEAD ciphers. The ssl_prefer_server_ciphers off directive is correct here—TLS 1.3 clients are trusted to choose appropriate ciphers.
Intermediate Configuration (TLS 1.2 + 1.3)
For broader compatibility while maintaining strong security:
# /etc/nginx/conf.d/ssl-hardening.conf
# Mozilla Intermediate Configuration - TLS 1.2 + 1.3
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;
# Session settings (required for TLS 1.2)
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# DH parameters for DHE ciphers
ssl_dhparam /etc/nginx/dhparam.pem;
# OCSP Stapling (for CAs that support it - see note below)
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.53 valid=300s;
resolver_timeout 5s;
If you’re using the Intermediate configuration with DHE ciphers, you need Diffie-Hellman parameters. Mozilla provides pre-generated, safe parameters:
The server_tokens off directive prevents NGINX from disclosing its version number in error pages and the Server response header. This is a basic security hardening measure that reduces information disclosure to potential attackers.
The ssl_trusted_certificate directive is required for OCSP stapling to work with CAs that support OCSP. It should point to the certificate chain file (intermediate certificates).
If you’re interested in the latest protocols, you can also enable HTTP/3 (QUIC) on NGINX for even better performance.
Step 4: Configure HSTS (HTTP Strict Transport Security)
HSTS tells browsers to only connect to your site over HTTPS, preventing downgrade attacks and SSL stripping:
Important: Let’s Encrypt No Longer Supports OCSP
As of 2025, Let’s Encrypt has discontinued OCSP support. Their OCSP responders were shut down and new certificates no longer include OCSP URLs. If you’re using Let’s Encrypt certificates, the ssl_stapling directives will have no effect—NGINX will simply skip OCSP stapling silently.
This change reflects the industry’s move toward:
– Shorter certificate lifetimes (90 days) that limit exposure from compromised certificates
– Certificate Transparency logs for public monitoring of certificate issuance
– CRLite and other emerging revocation checking mechanisms
For Let’s Encrypt users: You can safely remove the OCSP stapling directives from your configuration, or leave them in place (they won’t cause errors, just won’t do anything).
For other CAs: Commercial Certificate Authorities like DigiCert, Sectigo, and GlobalSign still support OCSP. If you use certificates from these providers, keep OCSP stapling enabled for the performance and privacy benefits.
Resolver Security Considerations
The resolver directive specifies DNS servers for OCSP queries. Using external resolvers like 8.8.8.8 or 1.1.1.1 introduces a security risk—a DNS spoofing attack could poison the resolver cache.
Best practices for the resolver:
Use a local resolver: 127.0.0.53 (systemd-resolved) or 127.0.0.1 (local DNS cache)
If using external resolvers: Enable DNSSEC validation on your local resolver
Cloud environments: Use the provider’s internal DNS (e.g., 169.254.169.253 for AWS)
The industry-standard test for SSL configuration is Qualys SSL Labs Server Test. Enter your domain and verify you receive an A+ rating.
Key metrics to check:
Protocol Support: Only TLS 1.2 and 1.3 (or TLS 1.3 only for Modern)
Gixy is a powerful NGINX configuration analyzer that detects security misconfigurations automatically. It checks for TLS issues, header problems, and many other security concerns.
Install Gixy on RHEL-based systems:
Understanding the ssl_prefer_server_ciphers Warning
Gixy may report a MEDIUM severity warning about ssl_prefer_server_ciphers off. This warning can be safely ignored when using Mozilla’s Intermediate or Modern configurations. Here’s why:
The disagreement explained:
Traditional security advice (including SSL Labs’ best practices) recommends ssl_prefer_server_ciphers on to force the server to choose ciphers, preventing clients from negotiating weak options.
However, Mozilla’s reasoning is different: when all ciphers in your list are secure (as they are in Mozilla’s curated configurations), there’s no weak cipher for a client to choose. In this case, letting the client choose (off) allows them to optimize for their hardware—mobile devices without AES-NI may perform better with ChaCha20-Poly1305, while servers with hardware acceleration benefit from AES-GCM.
When to use each setting:
Cipher Configuration
ssl_prefer_server_ciphers
Reason
Mozilla Modern/Intermediate
off
All ciphers are secure; let clients optimize for their hardware
Custom list with mixed ciphers
on
Force server to choose strongest cipher
Legacy compatibility (weak ciphers)
on
Essential to prevent weak cipher negotiation
The Mozilla configurations include only secure ciphers, so ssl_prefer_server_ciphers off is the correct choice for optimal client performance without sacrificing security.
Common Mistakes and How to Avoid Them
Mistake 1: Missing ssl_trusted_certificate
Without this directive, OCSP stapling fails silently (for CAs that support OCSP):
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found
Mistake 3: Using Session Tickets Without Key Rotation
If you enable ssl_session_tickets on, you must implement key rotation, otherwise the session ticket key could be compromised:
# Either disable session tickets
ssl_session_tickets off;
# Or implement key rotation with ssl_session_ticket_key
ssl_session_ticket_key /etc/nginx/ticket.key;
For most deployments, simply disabling session tickets is the safest approach.
Mistake 4: Using External DNS Resolvers
External resolvers like 8.8.8.8 can be vulnerable to DNS spoofing. Always prefer local resolvers for OCSP queries.
Performance Considerations
TLS 1.3 Performance Benefits
TLS 1.3 inherently improves performance:
1-RTT handshakes: Standard connections complete in one round-trip
0-RTT resumption: Returning clients can send data immediately (with security tradeoffs)
Session Cache Sizing
The ssl_session_cache shared:SSL:10m directive allocates 10 MB of shared memory for the session cache. Each megabyte stores approximately 4,000 sessions:
TLS 1.3’s preferred X25519 key exchange is faster than traditional ECDHE-P256, reducing CPU overhead. The cipher suite CHACHA20-POLY1305 is particularly efficient on servers without AES-NI hardware acceleration.
Complete Configuration Example
Here’s a production-ready complete configuration combining all elements:
# /etc/nginx/conf.d/ssl-hardening.conf
# Mozilla Intermediate Configuration for NGINX
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;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_dhparam /etc/nginx/dhparam.pem;
# OCSP Stapling (works with commercial CAs; no effect with Let's Encrypt)
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.53 valid=300s;
resolver_timeout 5s;
Hardening plus continuous monitoring. An A+ rating today is no guarantee of an A+ rating after the next config change. ssl_protocols and ssl_ciphers directives drift across server blocks more often than you would think. GetPageSpeed Amplify runs scheduled gixy scans across every host and ties findings to live NGINX runtime metrics. Drop-in compatible with the deprecated nginx-amplify-agent (EOL January 2026).
]]>