TLS 1.2 and 1.3 Cipher Hygiene Without SSL Labs Cargo Cult
Tune TLS 1.2 and 1.3 plus ciphers for nginx without cargo-cult SSL Labs chasing, and read a test grade as a checklist rather than a trophy hunt.
Netbay Cloud Team
Netbay Engineering
On this page
An A+ on a public scanner is not a security program. It is a snapshot of protocol versions, cipher suites, and a handful of headers on one hostname. Chasing the last yellow box often means copying a 2018 mozilla.org snippet that disables TLS 1.2 clients you still have, or enabling OCSP stapling you never monitor. This post is the small nginx TLS surface that matters on a VPS: 1.2 plus 1.3, AEAD ciphers, a sane certificate chain, and how to read a scanner without worshipping it.
The certificate you already issued with certbot is the identity. Cipher hygiene is how you talk after the name matches. Mixing those two jobs is why people reissue a valid cert because a scanner mentioned "weak DH."
Protocols: drop the fossils, keep 1.2 until you know the clients
ssl_protocols TLSv1.2 TLSv1.3; is the current default you want on a public site. TLS 1.0 and 1.1 are broken by modern policy. TLS 1.3 is faster (1-RTT, no RSA key exchange) and has a tiny cipher menu, which is a feature. Disabling TLS 1.2 because a blog said "1.3 only" will lock out older Android, some corporate proxies, and payment callbacks. Measure your logs before you drop 1.2.
You do not set TLS 1.3 ciphers the same way as 1.2. In nginx, ssl_ciphers affects 1.2. ssl_conf_command Ciphersuites (OpenSSL 1.1.1+) affects 1.3. If you paste a giant 1.2 cipher string into a 1.3-only thought process, you are not doing what you think.
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com;
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 off;
ssl_ciphers HIGH:!aNULL:!MD5:!3DES:!RC4:!PSK;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
}ssl_prefer_server_ciphers off is correct for TLS 1.3 and for modern 1.2 clients that know their hardware (AES-NI versus ChaCha). Forcing a server order from a 2016 snippet is cargo cult.
Ciphers: AEAD, no 3DES, no RC4, no static RSA if you can avoid it
What you want on 1.2: ECDHE plus AES-GCM or ChaCha20-Poly1305. What you do not want: RC4, 3DES, export, NULL, MD5, and anonymous DH. Ubuntu 24.04's OpenSSL already excludes most of that. A short ssl_ciphers that says HIGH and then bang-excludes the fossils is easier to review than a 400-character Mozilla intermediate paste you never update.
RSA key exchange (the old "TLS_RSA_WITH_AES_128_CBC_SHA") has no forward secrecy. If the scanner says "not FS," add ECDHE, not a new certificate. The cert is unrelated.
Test with openssl, not only a website:
openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null
nmap --script ssl-enum-ciphers -p 443 example.comIf -tls1_0 still handshakes, your ssl_protocols did not apply to the server block that actually won default_server. nginx -T is the truth.
How to read SSL Labs without performing for it
A typical report has protocol, cipher, certificate, and "protocol details" (HSTS, ticket keys, OCSP). Fix in that order:
- Certificate: name match, not expired, chain complete (fullchain.pem). An incomplete chain is a real user-facing bug.
- Protocols: no SSL 3, no TLS 1.0/1.1.
- Ciphers: no RC4/3DES/NULL; prefer AEAD.
- Optional: HSTS, OCSP staple, CAA.
HSTS (Strict-Transport-Security) is not a TLS setting. It is a header that tells browsers to skip HTTP next time. Enable it after you are sure nothing on the hostname must speak HTTP, including APIs and old bookmarks. A max-age of a year with includeSubDomains on a domain that still has a forgotten HTTP tool is a self-inflicted lockout. OCSP stapling is fine if nginx can reach the CA responder; if it cannot, you have added a dependency for a grade.
Do not disable TLS 1.2 to turn a B into an A if your users still need 1.2. Do not buy a commercial cert to fix a cipher finding. Do not copy ssl_dhparam from a random gist that is 1024 bits.
Cipher hygiene on a VPS is a short nginx block, a complete Let's Encrypt chain, and a scanner used as a diff against last month. The grade is a report, not a goal. You can apply this config on a Netbay Ubuntu instance in Lucknow (DC01) on Xeon Platinum with High-Speed SSD and follow the handshake from a laptop — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance