Why TLS Hardening Matters
Transport Layer Security (TLS) is the first line of defense for any web service. A mis‑configured Nginx instance can expose your site to downgrade attacks, weak cipher suites, and man‑in‑the‑middle snooping. For a DevOps lead, a solid checklist turns a vague "secure the site" task into a repeatable, auditable process.
Checklist Overview
Below is a practical, step‑by‑step checklist you can run after each Nginx deployment. Treat it as a pre‑flight routine before you flip the DNS switch.
1. Enforce Modern Protocol Versions
- Disable SSLv2, SSLv3, TLS 1.0, and TLS 1.1.
- Enable TLS 1.2 and TLS 1.3 (if your OpenSSL version supports it).
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
2. Choose Strong Cipher Suites
Prefer ciphers that provide AEAD (Authenticated Encryption with Associated Data) and PFS (Perfect Forward Secrecy). A sane default list looks like this:
ssl_ciphers \
"TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256" \
"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384" \
"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256";
Avoid the !aNULL
and !MD5
shortcuts; list the exact suites you trust.
3. Enable Perfect Forward Secrecy (PFS)
PFS is baked into the cipher list above, but you can double‑check by generating a strong Diffie‑Hellman parameter file:
# Generate a 4096‑bit DH params file (run once)
openssl dhparam -out /etc/nginx/dhparam.pem 4096
Then reference it in your config:
ssl_dhparam /etc/nginx/dhparam.pem;
4. Turn on HTTP Strict Transport Security (HSTS)
HSTS forces browsers to only use HTTPS for your domain, preventing protocol‑downgrade attacks.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Remember to test the preload
flag with the official Chrome list before committing.
5. Deploy OCSP Stapling
OCSP stapling reduces latency and hides the client‑side OCSP request from attackers.
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
6. Harden Session Tickets
If you enable TLS 1.3, session tickets are the default. Rotate the ticket key regularly:
# Generate a new ticket key (rotate weekly)
openssl rand -hex 48 > /etc/nginx/ticket.key
ssl_session_ticket_key /etc/nginx/ticket.key;
7. Set Secure Cookie Flags
Force cookies to be sent only over HTTPS and make them inaccessible to JavaScript.
add_header Set-Cookie "Secure; HttpOnly; SameSite=Strict" always;
8. Automate Certificate Renewal
Use certbot (or your ACME client of choice) with a systemd timer to keep certs fresh.
# Example certbot timer (runs twice daily)
systemctl enable --now certbot.timer
9. Test Your Configuration
Run the SSL Labs test or use testssl.sh
locally:
# Quick local test
testssl.sh https://yourdomain.com
Aim for an A+ rating and verify that only the ciphers you listed appear.
10. Log and Monitor TLS Errors
Add a dedicated error log for TLS handshake failures. This helps you spot attacks early.
error_log /var/log/nginx/tls_errors.log warn;
Then ship the log to your central aggregator (e.g., Loki, Graylog) and set an alert on spikes.
Putting It All Together
Below is a minimal, production‑ready snippet that combines the above steps. Paste it into your server {}
block and reload Nginx.
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# TLS basics
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256";
ssl_dhparam /etc/nginx/dhparam.pem;
# HSTS & security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header Referrer-Policy "no-referrer-when-downgrade";
add_header Set-Cookie "Secure; HttpOnly; SameSite=Strict" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout 5s;
# Session tickets
ssl_session_ticket_key /etc/nginx/ticket.key;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/tls_errors.log warn;
# Your usual location blocks go here…
}
Reload with nginx -t && systemctl reload nginx
and verify the output of openssl s_client -connect localhost:443 -tls1_3
.
Final Thoughts
TLS hardening is a moving target: new cipher suites are deprecated, and browsers add support for TLS 1.3 at different speeds. Treat this checklist as a living document—review it quarterly, automate the parts you can, and keep an eye on the security bulletins for OpenSSL and Nginx.
If you’re looking for more hands‑on guidance or managed hosting that respects these hardening practices out of the box, consider checking out https://lacidaweb.com for a straightforward, developer‑friendly solution.
Top comments (0)