"TLS Configuration Guide: Protocols, Ciphers, Certificates and the Redirect Everyone Forgets"

HTTPS has a deceptively simple scorecard: either the padlock shows or it doesn't. Underneath, TLS configuration is a layered system — protocol versions, cipher suites, certificate chains, key sizes, HSTS, redirects — and failures rarely announce themselves. A server can negotiate TLS 1.0 with RC4 for one client and TLS 1.3 with AES-GCM for another; the padlock looks identical to both. Expired and self-signed certificates produce browser warnings that a shocking number of users click through. And the most common real-world TLS failure isn't cryptographic at all: it's the missing HTTP-to-HTTPS redirect that leaves every http:// link — from old bookmarks, email campaigns and printed URLs — landing in plaintext.

This guide covers each layer in turn: what modern configuration looks like, what an attacker actually does with each weakness, and how to fix it without breaking legacy clients you may or may not care about. The free security scan checks all of it in one pass — protocol versions, negotiated cipher, certificate chain and expiry, key size, HSTS and the redirect — and if you haven't hardened your response headers yet, pair this with our security headers guide.

Table of contents

  1. Protocol versions: what to enable in 2026
  2. Cipher suites: the part everyone gets wrong
  3. Certificates: chains, expiry, self-signing and mismatch
  4. Key sizes: why 1024-bit RSA is a finding
  5. The HTTP-to-HTTPS redirect
  6. HSTS: pinning the browser to HTTPS
  7. A hardening checklist
  8. Frequently asked questions

Protocol versions: what to enable in 2026

TLS versions are not flavors — each one replaces the security model of its predecessor:

  • TLS 1.3 (2018). The current standard: faster handshakes (1-RTT), forward secrecy mandatory, and an entire graveyard of legacy primitives removed. If your server negotiates TLS 1.3, that connection is using AEAD ciphers only — no CBC, no RC4, no static RSA key exchange.
  • TLS 1.2 (2008). Still safe when configured correctly. It allows both excellent suites (ECDHE + AES-GCM) and terrible ones (static RSA, CBC, 3DES), so its security depends entirely on your cipher configuration. Practically, you keep 1.2 enabled for one reason: some older corporate clients and Java versions still speak it best.
  • TLS 1.0 / 1.1. Formally deprecated by the IETF in 2021, disabled by default in every major browser since 2020, and non-compliant with PCI DSS. They lack modern handshake protections and are limited to weak primitives. Their remaining users are not customers you want: they are malware families that deliberately downgrade.
  • SSL 3.0 and earlier. Cryptographically dead — SSL 3.0 is the protocol POODLE broke in 2014 to demonstrate padding-oracle attacks on its CBC design. Any server still answering an SSLv3 handshake is Critically misconfigured.

The correct 2026 configuration is nearly universal:

# nginx
ssl_protocols TLSv1.2 TLSv1.3;
# Apache
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1

On Cloudflare, the edge handles this for you (set the minimum TLS version in SSL/TLS → Edge Certificates), but verify your origin speaks at least TLS 1.2 too — "Full (strict)" mode actually checks it.

One operational warning: before removing TLS 1.0/1.1, check your traffic logs for the clients that still use them. If a partner's ancient appliance breaks, you'll want to have made that decision consciously, with a migration deadline, rather than discover it in a 2 a.m. pager alert.

Cipher suites: the part everyone gets wrong

A protocol version says how to talk; the cipher suite says what to talk with. Each suite names the key-exchange algorithm, the bulk cipher, and the message-authentication code — TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 reads as: ECDHE key exchange (forward secrecy), RSA authentication, AES-256-GCM encryption.

Three families still appear in real configurations and should not:

  • RC4 — a stream cipher with decades of published biases; attacks recover session cookies from encrypted traffic (the 2013 "Lucky 13"/RC4-bias era). Browsers dropped it in 2016; servers occasionally still offer it "for compatibility".
  • 3DES — the Triple-DES stopgap, limited to a 64-bit block size. Sweet32 (2016) demonstrated birthday-bound collisions that leak plaintext blocks on long connections. Also 2016-era browsers-removed.
  • Static-RSA CBC suites (TLS_RSA_WITH_AES_128_CBC_SHA and friends) — no forward secrecy: whoever records your traffic today can decrypt it if the server's private key ever leaks, retroactively. Combined with CBC MAC-then-encrypt weaknesses (Lucky13 padding oracles), this family offers nothing but backwards compatibility.

The fix on nginx is a modern suite list plus server-side preference:

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 on;

(Everything listed negotiates forward secrecy and AEAD encryption; TLS 1.3 suites are implicit and always safe.) A useful sanity rule: if a suite name contains RC4, 3DES, or RSA_ without ECDHE_/DHE_, it should not be in the list.

Why the negotiated suite is a coin flip worth checking: your server offers a menu; the client picks. A scanner that connects twice — once modern, once deliberately downgraded — often finds the weak offering only the second time. This is why TLS auditing tools report both what you negotiated and what you offer; our scan checks the negotiated result, which catches the most damaging case (the server's best answer being weak), and cipher-offer audits (testssl.sh, sslscan) complement it.

Certificates: chains, expiry, self-signing and mismatch

A TLS certificate is only as trustworthy as its chain, its dates, its key, and the name on it. Four distinct failures, four distinct symptoms:

Expired certificates

The most common TLS finding on the entire internet. An expired certificate converts every visit into a full-page interdiction warning — and click-through rates on those warnings are high enough that attackers have built entire phishing kits around them. Modern operations answer is automation: Let's Encrypt via certbot (90-day certs, renewable cron/systemd timer) or your cloud's auto-renewal. Whatever you pick, monitor it externally — internal renewal jobs fail silently, and the first alert should never be a customer's screenshot. The scan flags certificates inside the policy warning window (default: 30 days) so renewal has runway.

Self-signed certificates

A self-signed certificate says "I am me, trust me" with no witness. Any attacker can mint one; nothing binds it to your domain. They're appropriate for localhost development and nowhere else in production. If an internal service needs TLS without a public CA, run a private CA (or use ACME against an internal CA like step-ca) and distribute trust properly.

Hostname mismatch

A certificate for www.example.com presented at api.example.com (or a wildcard *.example.com that doesn't cover deep.api.example.com) breaks the name-binding that underpins the whole system. Browsers refuse; users override; attackers benefit. With Let's Encrypt there is no cost excuse — issue per-hostname certs or a correct wildcard via DNS-01.

Broken chains

Servers that forget the intermediate certificate work in many desktop browsers (which cache intermediates and silently "fix" the chain) and fail on mobile devices, curl, Java clients and embedded devices. The failure is therefore intermittent-by-audience and maddening to debug from a working laptop. Test with openssl s_client -connect host:443 -servername host and check the chain depth: leaf, then intermediate(s), then root must all appear (root optional on the wire). certbot and managed load balancers assemble chains correctly; hand-assembled fullchain.pem files (leaf + intermediate concatenated) are where mistakes live.

Key sizes: why 1024-bit RSA is a finding

A 1024-bit RSA key is not yet broken in public, but it sits below every modern assurance threshold: NIST disallowed RSA-1024 for new keys over a decade ago, and nation-state-scale factoring continues to improve. A finding here is cheap to fix and awkward to defer: generate a 2048-bit (or 3072-bit) key, or switch to ECDSA (P-256) — smaller, faster, increasingly the default with modern CAs. Note that Let's Encrypt issues ECDSA chain certs today (certbot --key-type ecdsa), and mixed RSA+ECDSA deployments via multiple ssl_certificate lines are fully supported on nginx 1.11+.

The key size matters most in the static-RSA scenario from the cipher section: weak key plus no forward secrecy is the combination that makes recorded traffic retroactively decryptable. Strong key + ECDHE removes both halves of that problem.

The HTTP-to-HTTPS redirect

Here is the failure mode we flag most often on scans that "have HTTPS working": https://example.com is perfectly configured, while http://example.com — every plaintext link arriving from old emails, QR codes, printed materials, third-party aggregators — returns 200 OK over plaintext with no redirect. The site is encrypted for anyone who types the right scheme and wide open for everyone else.

The check is one request:

# nginx: dedicated redirect server block
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}
# Apache vhost on :80
RewriteEngine On
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Cloudflare: SSL/TLS → Edge Certificates → Always Use HTTPS. Application-level redirects (middleware checking the scheme) work too but cover only the app's routes — a server-level redirect covers everything, including files and paths you forgot exist.

Two details that separate a good redirect from a partial one:

  1. Preserve the path. return 301 https://$host$request_uri; keeps deep links working; a bare redirect to the homepage quietly breaks every inbound deep link and your SEO at the same time.
  2. Never downgrade. The reverse misconfiguration — an HTTPS page whose redirect chain hops back to HTTP — is its own finding: the security of the final connection is the weakest link in the chain.

HSTS: pinning the browser to HTTPS

The redirect has a residual gap: the first request on a fresh device still travels plaintext before the server can redirect it, and a network attacker intercepts it there. HSTS closes the gap after first contact by instructing browsers to refuse HTTP to your domain outright for the policy duration:

Strict-Transport-Security: max-age=31536000; includeSubDomains

Deploy it in stages (300 seconds → 30 days → 1 year), add includeSubDomains only after auditing every subdomain, and reserve preload for domains you're certain about — inclusion in the browser-baked preload list is effectively permanent. The full reasoning and rollout ladder is in the security headers guide; the TLS-specific note is that the scan checks HSTS max-age from the TLS handshake perspective too — a policy below the recommended minimum (six months for production domains) gets flagged, because short max-ages leave long-horizon attackers a downgrading window.

A hardening checklist

In deployment order, with the failure each step removes:

  1. Obtain a real certificate with automated renewal (Let's Encrypt + certbot or managed LB) — removes expiry and self-signing findings forever.
  2. Serve the full chain — removes the mobile/embedded-client breakage that desktop testing misses.
  3. ssl_protocols TLSv1.2 TLSv1.3; — removes downgrade-to-TLS-1.0/SSLv3 exposure.
  4. Modern cipher list, server preference on — removes RC4/3DES/static-RSA negotiation.
  5. 2048-bit RSA or ECDSA keys — removes the retroactive-decryption risk.
  6. Port-80 → HTTPS 301 with path preserved — fixes the plaintext side-door.
  7. HSTS ramp (300s → 1 year → includeSubDomains → preload) — removes the first-request gap.
  8. External monitoring — certificates and configs drift; re-scan after infrastructure changes, not just once.

Steps 1–6 are typically one afternoon. Step 7 is a deliberate, staged rollout. Step 8 is what keeps the other seven true.

Frequently asked questions

Do I still need TLS 1.2 if TLS 1.3 is enabled?

Yes, for now — a long tail of enterprise proxies, older Java/Android clients and some bots still negotiate 1.2 only. TLS 1.3 alone would lock them out. Enable both; 1.3 clients use 1.3 automatically.

Is a certificate for www. enough for the apex domain?

No — www.example.com and example.com are different names. Modern CAs include both in one certificate (Let's Encrypt does), but verify the SAN list covers every name you serve.

How long should my certificate live?

Short. The industry has converged on ~90-day automated certificates precisely because long-lived certs make revocation and key rotation meaningless. With automation, shorter is strictly safer.

My scan says the certificate is expiring soon but certbot renewed it — why?

Server-side renewal doesn't always reload the service. Check what's actually being served (openssl s_client -connect host:443 -servername host | openssl x509 -noout -dates); if it's the new cert, the scan result was cached from before renewal — rerun it.

Why does my site work in Chrome but fail in an Android app?

Almost always the missing intermediate certificate: desktop browsers cache intermediates and repair broken chains silently; mobile apps using the OS trust store do not. Test the chain with openssl, not just the browser.


Run the free security scan for a full TLS report on your domain — protocol, cipher, certificate chain, expiry countdown, key size, redirect and HSTS in one pass.