A surprising number of production web applications are still running TLS configurations from 2018: TLS 1.0 or 1.1 enabled, weak cipher suites accepted, certificates renewed by hand, no HSTS. These aren't edge cases. They are common findings in infrastructure audits. The consequences range from failed PCI DSS compliance to actively exploitable downgrade attacks.
Here is a current, practical guide to TLS configuration that reflects 2026 standards and threats.
Protocol Versions: TLS 1.3 Only (Almost)
TLS 1.2 remains acceptable. TLS 1.0 and 1.1 must be disabled. They are vulnerable to BEAST, POODLE and SLOTH attacks and have been deprecated by every major standards body. PCI DSS has not allowed them for cardholder data since 2018, and version 4.0 keeps that rule.
TLS 1.3 is the target. It removes the entire renegotiation mechanism that enabled many historical attacks, cuts the handshake to one round trip (versus two for TLS 1.2), and supports only forward-secret cipher suites. On Nginx:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
Setting ssl_prefer_server_ciphers off with TLS 1.3 lets the client choose from the supported cipher suites, which are all secure, so modern clients can use their fastest implementation.
Cipher Suites: Prioritize Forward Secrecy
Forward secrecy (Perfect Forward Secrecy, PFS) ensures that a future compromise of your private key cannot decrypt past recorded traffic. It works by using ephemeral session keys that are never written to disk. TLS 1.3 requires forward secrecy, since all its cipher suites use ephemeral Diffie-Hellman. For TLS 1.2, enforce it explicitly:
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;
Every cipher in this list starts with ECDHE (Elliptic Curve Diffie-Hellman Ephemeral), which is what guarantees forward secrecy. Exclude anything with RC4, DES, 3DES, NULL, EXPORT, or MD5.
Certificate Management: Automate Everything
Manual certificate renewal is a liability. Expiry incidents, where a production site shows certificate errors to real users, almost always come from a manual process someone forgot. Certificate lifetimes are also shrinking: the CA/Browser Forum approved a phased cut from 398 days down to 47 days by 2029, so renewal has to be automated.
Let's Encrypt + Certbot remains the standard for most deployments. Install certbot, run certbot --nginx once, and it configures auto-renewal via a systemd timer or cron job:
# Install and issue
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Test renewal
sudo certbot renew --dry-run
For Docker/Traefik environments, Traefik handles ACME certificate issuance and renewal automatically through its Let's Encrypt integration, with no manual certbot needed. Certificates are stored in a JSON file that persists across container restarts.
Certificate monitoring is still necessary even with automation. Tools like cert-expiry-check or Grafana alerting on certificate expiry metrics catch failures in renewal automation before users do. Set alerts at 30-day and 7-day thresholds.
HSTS: Tell Browsers to Always Use HTTPS
HTTP Strict Transport Security (HSTS) instructs browsers to refuse HTTP connections to your domain and always upgrade to HTTPS, even before the server can redirect. This eliminates the window for SSL stripping attacks on users who type your domain without https://.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
The max-age of 63072000 seconds (2 years) is the minimum required for HSTS preloading. includeSubDomains extends coverage to all subdomains, so make sure every subdomain has a valid certificate before you enable it. preload opts into the browser-maintained HSTS preload list, meaning users who have never visited your site are still protected.
Submit your domain to the preload list at hstspreload.org once you have a stable configuration. Removal takes months, so only enable preload when you're committed to HTTPS-only operation.
OCSP Stapling: Faster Certificate Validation
When a browser connects to your server, it may check whether your certificate has been revoked, which means a round trip to the Certificate Authority's OCSP responder. That slows the TLS handshake and depends on a third-party service. OCSP stapling removes the round trip: your server fetches the OCSP response ahead of time and "staples" it to the handshake. Note that Let's Encrypt stopped running OCSP in 2025, so stapling only applies to certificates from CAs that still offer it.
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
Testing Your Configuration
Two tools cover most of what you need:
SSL Labs Server Test (ssllabs.com/ssltest) grades your TLS configuration against current best practices. Aim for A+. Common reasons for failing A+: missing HSTS header, TLS 1.0/1.1 still enabled, weak cipher suites in the supported list.
testssl.sh: open-source command-line tool for testing any server without sending data to a third party. Useful for internal services, staging environments, and CI pipeline integration:
./testssl.sh --full yourdomain.com
Configuration Checklist
- TLS 1.0 and 1.1 disabled
- TLS 1.3 enabled, and TLS 1.2 with forward-secret cipher suites only
- Certificate auto-renewal configured and tested
- Certificate monitoring alerts set at 30 days and 7 days
- HSTS header with
max-age=63072000andincludeSubDomains - OCSP stapling enabled
- HTTP to HTTPS redirect on port 80
- SSL Labs score: A or A+
- No mixed content warnings (all sub-resources loaded over HTTPS)
TLS configuration is not set-and-forget. New vulnerabilities are discovered, cipher suite recommendations evolve, and CA policies change. Schedule a quarterly review of your TLS posture against current Mozilla SSL Configuration Generator recommendations, and run SSL Labs after every major Nginx or certificate infrastructure change.