Your site loads over HTTPS. The padlock is green. Then one day the alert comes: 'certificate expired', 'handshake failed', 'TLS version deprecated'. The client doesn't understand, traffic drops, Google penalizes. We at Meteora Web see it every day in projects coming for a security audit. TLS is not a checklist checkbox — it's a living protocol with dying versions, aging configurations, and handshakes that must balance security and latency.
This guide is for those who already know what a certificate is but want to understand how the handshake really works, which versions to use, and how to avoid common configuration pitfalls.
The TLS Handshake: What Happens in Those Milliseconds
Every time a browser connects to your HTTPS server, a negotiation happens in 4–7 steps. If one step fails, no connection. If it's slow, the user perceives delay. We optimized TLS handshakes for e-commerce clients, cutting time-to-first-byte by 30% just by fixing TLS configuration.
Step 1: Client Hello
The browser sends a message with the TLS versions it supports (e.g., 1.2, 1.3), preferred cipher suites, and a random number. The server receives and chooses the most secure combination from the list.
Sponsored Protocol
Step 2: Server Hello and Certificate Exchange
The server responds with the chosen version, cipher suite, its own random, and its X.509 certificate. Common mistake: the certificate must include the full trust chain (root CA + intermediate), otherwise the browser rejects it. We've seen servers with incomplete chains causing failures on Android clients.
Step 3: Key Exchange and Verification
With TLS 1.2, there's an additional exchange to establish a symmetric key (usually ephemeral Diffie-Hellman). With TLS 1.3, all happens in one round-trip, reducing latency. After that, client and server confirm the handshake is complete and start exchanging encrypted data.
Common mistake: not using ECDHE (Elliptic Curve Diffie-Hellman Ephemeral). Servers configured only with RSA expose passive attacks. At Meteora Web we always enforce ECDHE with P-256 or X25519 curves on our deployments.
Secure Versions: TLS 1.2, 1.3, and the Old Relics
Today the only versions you should accept are TLS 1.2 and 1.3. TLS 1.0 and 1.1 are deprecated by all modern browsers and by PCI DSS. SSLv3 and below must be blocked brutally. But beware: just disabling them is not enough; you must ensure the server does not offer them during negotiation. We've seen Apache configs claiming to support only 1.2 yet accepting downgrades if the client insists.
Sponsored Protocol
Why TLS 1.3 is Better
- Fewer round-trips: handshake completes in 1 RTT (vs 2 in 1.2). With session resumption, even 0-RTT (but beware of replay risks).
- Stronger ciphers: abandons RSA and CBC, accepts only AEAD (AES-GCM, ChaCha20-Poly1305).
- Mandatory Perfect Forward Secrecy: if the private key is compromised, past sessions remain secure.
We recommend enabling TLS 1.3 immediately, and keeping TLS 1.2 as a fallback for legacy clients (e.g., browsers on unpatched Windows 7). Never go below 1.2.
Certificates: More than Expiration
Certificates have a hierarchy: Root CA (natively trusted) -> Intermediate CA -> your domain. If the server doesn't send the intermediate, many clients (especially mobile) fail validation. We always verify with openssl s_client -connect domain:443 -showcerts.
Certificate Types
- DV (Domain Validated): just prove domain control. Fine for normal sites.
- OV (Organization Validated): also verifies the company. Gives more visual trust (though few notice).
- EV (Extended Validation): showed green bar in the browser. Nearly obsolete now — browsers show it as a note, not green. We no longer recommend it; the extra cost doesn't justify the benefit.
Automation with Let's Encrypt
We use certbot on almost every server: automatic renewal every 90 days. Caution: we've seen servers where the cron job breaks and the certificate expires without notice. The fix: test renewal with certbot renew --dry-run weekly and monitor expiration with UptimeRobot or Prometheus.
Sponsored Protocol
Example Nginx config (minimal secure server block):
server {
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;
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;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000" always;
}Note: ssl_prefer_server_ciphers off because TLS 1.3 handles selection natively. For TLS 1.2, it's better to keep it on.
Sponsored Protocol
Verifying Your Configuration: Tools and Commands
Before going live, we always run these checks:
- SSL Labs (Qualys): comprehensive online test. We aim for A+.
- testssl.sh: command-line script, great for CI/CD. Example:
./testssl.sh --quiet https://yourdomain.com - OpenSSL s_client: for low-level debugging.
openssl s_client -connect domain:443 -tls1_3shows handshake details.
Common Mistakes and How to Fix Them
Name/SAN Mismatch
The certificate must include the exact domain name in the Subject Alternative Name (SAN) field. If you have example.com and www.example.com, both must be present. We use wildcard certificates (*.example.com) only when many subdomains are needed, but beware: they don't cover the naked domain.
Incomplete Chain
Let's Encrypt's fullchain.pem already contains the full chain. If you use a commercial CA, concatenate the certificate and intermediate into one file. Verify with: openssl verify -CAfile trusted-root.pem -untrusted intermediate.pem cert.pem.
Missing HSTS
The Strict-Transport-Security header forces the browser to use only HTTPS for the domain. Without it, a MITM attack can downgrade to HTTP. Set a max-age of at least 6 months (63072000 seconds); after verifying everything works in HTTPS, add includeSubDomains and preload (but only if you're sure).
Sponsored Protocol
In Summary — What to Do Now
If you manage servers or develop APIs, take these immediate actions:
- Check which TLS versions your server supports. Use testssl.sh or SSL Labs. Block TLS 1.0 and 1.1 immediately.
- Verify the certificate chain with
openssl s_client -showcerts. If an intermediate is missing, rebuild the concatenated file. - Enable TLS 1.3 and configure only secure ciphers (use the list above).
- Enable HSTS with an appropriate max-age. First verify no mixed content (HTTP and HTTPS) on your site.
- Automate certificate renewal and monitor expiration. Set an alert when 30 days remain.
- Test after every configuration change. A syntax error can take down the server.
This guide is part of our Cryptography and Data Security pillar guide. If you want to dive deeper into concepts like forward secrecy or TLS attacks, start there.
We at Meteora Web work with these protocols every day. If you have doubts about your configuration, don't wait for a client to report an error. Check it today.