Once you have a certificate (see the Let’s Encrypt recipe), this is a safe, modern HTTPS block aligned with the Mozilla “intermediate” profile.
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # Nginx 1.25.1+. Older: "listen 443 ssl http2;"
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Protocols & ciphers (Mozilla intermediate).
ssl_protocols TLSv1.2 TLSv1.3;
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;
ssl_prefer_server_ciphers off; # let modern clients pick (recommended for TLS 1.3)
# Session resumption.
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP stapling.
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
# Tell browsers to stick to HTTPS (only add once you're sure HTTPS works).
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
# ...your site or proxy_pass...
}
}
Notes:
fullchain.pem, notcert.pem— it includes the intermediate chain, or some clients show “incomplete chain” errors.- TLS 1.0/1.1 are omitted — they’re deprecated. Only re-add them if you must support truly ancient clients.
ssl_prefer_server_ciphers offis current best practice; TLS 1.3 negotiates its own ciphers and modern clients order them sensibly.- OCSP stapling needs a working
resolverso Nginx can fetch the OCSP response; without it stapling silently does nothing. - Add HSTS (
Strict-Transport-Security) only after confirming HTTPS is solid — it’s hard to undo because browsers cache it. See headerforge for the full header set includingincludeSubDomainsand preload.
sudo nginx -t && sudo nginx -s reload