SSL/TLS Best Practices 2026
A comprehensive guide to deploying and maintaining secure TLS configurations. Covers TLS 1.3 migration, cipher suite hardening, HSTS, automated certificate management, and production-ready server configs.
TLS 1.2 vs TLS 1.3 Comparison
| Feature | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Handshake RTT | 2-RTT | 1-RTT (0-RTT resumption) |
| Cipher suite count | 37+ (many weak) | 5 (all strong) |
| Forward Secrecy | Optional | Mandatory (ECDHE only) |
| CBC mode ciphers | Supported (BEAST/POODLE) | Removed |
| RSA key exchange | Supported (no FS) | Removed |
| SHA-1 / MD5 | Allowed in some configs | Removed |
| Encrypted handshake | Partial | Most fields encrypted |
| Browser support | Universal | 96%+ global (2026) |
Nginx: Modern TLS Configuration
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name yourapp.com www.yourapp.com;
# Certificate paths (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/yourapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourapp.com/privkey.pem;
# Modern TLS protocols (disable 1.0, 1.1)
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.3 ciphers (auto-selected, best practice to list explicitly)
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:DHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off; # Let client choose (TLS 1.3)
# Elliptic curves — prefer X25519, P-256
ssl_ecdh_curve X25519:prime256v1:secp384r1;
# Session resumption
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off; # Disable for forward secrecy
# OCSP stapling (reduces handshake latency)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/yourapp.com/chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=300s;
# DH params (generate: openssl dhparam -out /etc/nginx/dhparam.pem 2048)
ssl_dhparam /etc/nginx/dhparam.pem;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name yourapp.com www.yourapp.com;
return 301 https://$host$request_uri;
} Let's Encrypt: Automated Certificate Management
Initial Setup with Certbot
# Install certbot (Ubuntu/Debian) sudo apt install certbot python3-certbot-nginx # Obtain certificate + auto-configure nginx sudo certbot --nginx -d yourapp.com -d www.yourapp.com # Test renewal process sudo certbot renew --dry-run # Certbot auto-renewal is enabled via systemd timer: sudo systemctl status certbot.timer
acme.sh Alternative (More Flexible)
# Install acme.sh curl https://get.acme.sh | sh # Issue certificate (standalone mode) acme.sh --issue -d yourapp.com -d www.yourapp.com --standalone # Install to nginx paths acme.sh --install-cert -d yourapp.com \ --cert-file /etc/nginx/ssl/cert.pem \ --key-file /etc/nginx/ssl/key.pem \ --fullchain-file /etc/nginx/ssl/fullchain.pem \ --reloadcmd "systemctl reload nginx" # Renews automatically via cron (added by acme.sh installer)
Certificate Expiry Monitoring
#!/bin/bash
# check-cert-expiry.sh — run via cron, alert if < 30 days
DOMAIN="yourapp.com"
THRESHOLD=30 # days
EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null \
| cut -d= -f2)
EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
TODAY_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - TODAY_EPOCH) / 86400 ))
echo "Certificate expires in ${DAYS_LEFT} days"
if [ ${DAYS_LEFT} -lt ${THRESHOLD} ]; then
# Send alert (webhook, email, PagerDuty, etc.)
curl -X POST ${SLACK_WEBHOOK} \
-d "{\"text\":\"⚠️ TLS cert for ${DOMAIN} expires in ${DAYS_LEFT} days\"}"
fi Apache TLS Configuration
<VirtualHost *:443>
ServerName yourapp.com
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/yourapp.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourapp.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/yourapp.com/chain.pem
# Modern TLS only
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite 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
SSLHonorCipherOrder off # TLS 1.3 ignores this
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:/var/run/ocsp(128000)"
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost> TLS Security Checklist
| Check | Requirement | Verify With |
|---|---|---|
| Protocol version | TLS 1.2+ only | SSL Labs test |
| Forward secrecy | ECDHE or DHE key exchange | ssl-enum-ciphers |
| HSTS header | max-age ≥ 31536000 | curl -I yourhost |
| OCSP stapling | Enabled and verified | openssl s_client -status |
| Certificate chain | Complete chain, not expired | SSL Labs / certbot |
| Renewal automation | Certbot/acme.sh timer active | systemctl status certbot.timer |
| HTTP redirect | 301 from HTTP to HTTPS | curl -L http://yourhost |
Frequently Asked Questions
What is the difference between TLS 1.2 and TLS 1.3?▼
TLS 1.3 (RFC 8446, 2018) is a major redesign with significant improvements: 1-RTT handshake (vs 2-RTT in TLS 1.2), 0-RTT resumption for repeat connections, removal of all weak cipher suites (RC4, DES, 3DES, MD5, SHA-1, CBC mode), perfect forward secrecy is now mandatory (ephemeral ECDH only), and simplified cipher suite negotiation. TLS 1.3 is 30-40% faster for new connections and should be used exclusively. TLS 1.0 and 1.1 are deprecated by RFC 8996 and disabled in all modern browsers.
What is HSTS and how do I enable it?▼
HTTP Strict Transport Security (HSTS) tells browsers to only connect to your domain over HTTPS, even if the user types http://. Once a browser sees the Strict-Transport-Security header, it will automatically upgrade all future requests to HTTPS for the specified max-age duration, preventing SSL stripping attacks. Set: Strict-Transport-Security: max-age=63072000; includeSubDomains; preload (2 years). To add your domain to the HSTS preload list (hardcoded in browsers), submit at hstspreload.org — this is permanent, so only do it when fully committed to HTTPS.
How often should I rotate TLS certificates?▼
Let's Encrypt certificates expire every 90 days and should be renewed at 60 days (30 days before expiry). Commercial certificates are typically issued for 1 year (maximum since 2020). Best practice: automate renewal with certbot or acme.sh — never rely on manual renewal. Set up monitoring to alert when certificates are within 30 days of expiry. For internal services, use automated certificate management like HashiCorp Vault PKI Secrets Engine or AWS Certificate Manager Private CA.
What cipher suites should I use in 2026?▼
For TLS 1.3, cipher suites are fixed and non-negotiable: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256. For TLS 1.2 compatibility, use ECDHE+AESGCM+SHA256/384. Disable: CBC mode ciphers (BEAST/POODLE), RC4, 3DES, export ciphers, DH key exchange under 2048-bit. Mozilla's SSL Configuration Generator at ssl-config.mozilla.org is the gold standard reference and is updated as vulnerabilities are discovered.
What is certificate pinning and when should I use it?▼
Certificate pinning associates a specific TLS certificate (or public key hash) with an application, so the app refuses connections if the certificate doesn't match — even if it's signed by a trusted CA. It protects against compromised CAs or MITM with a fraudulently issued certificate. Use in: mobile apps with fixed server connections, high-security financial applications. Avoid for general web browsers (makes cert rotation difficult). Prefer public key pinning over full certificate pinning to allow cert renewal without app update. Google removed Chrome's HPKP support in 2018 due to site lockout risks.
How do I test my TLS configuration?▼
Use SSL Labs (ssllabs.com/ssltest) for a detailed A+ grade report including certificate chain, protocol versions, cipher suites, and known vulnerabilities (BEAST, POODLE, Heartbleed, ROBOT, etc.). Command-line testing: 'openssl s_client -connect yourhost:443 -tls1_3' to verify TLS 1.3 works. 'nmap --script ssl-enum-ciphers -p 443 yourhost' to enumerate all supported ciphers. 'testssl.sh' for comprehensive command-line testing. Run these tests after any server configuration change.
Related Products
on GumroadPremium Workflow Pack
Production-grade workflows, architecture guides, and deployment scripts for teams that ship. 10 advanced CI/CD workflows (blue-green, canary, E2E, security), 5 architecture deep-dives, code review checklist, PR process guide, and 5 battle-tested Bash deployment scripts.
Buy on Gumroad →DevPlaybook Interview Vault
210+ real technical interview questions with model answers, asked at Google, Meta, Amazon, Microsoft, Stripe, and Shopify. Covers Frontend (55), Backend (55), System Design (50), and DSA (50). Available in English and Traditional Chinese.
Buy on Gumroad →GitHub Actions CI/CD Templates Pack
12 production-ready GitHub Actions workflow templates covering Node.js, Python, Docker, multi-environment deployments, security scanning, and auto-changelog. Copy, paste, ship.
Buy on Gumroad →You Might Also Need
Webhook Tester
Generate realistic webhook test payloads for GitHub, Stripe, Slack, and custom services. Get a curl command to send the payload to your local endpoint. Inspect headers, payload size, and content-type.
Open free tool →
WebSocket Tester
Connect to any WebSocket server, send and receive messages in real time, and inspect the message log with timestamps and byte sizes. Free online WebSocket client.
Open free tool →
WebP Converter
Convert PNG, JPG, or GIF images to WebP format in your browser. Drag-and-drop upload, quality slider, before/after file size comparison. No files sent to any server.
Open free tool →
More Free Tools
Related Articles
Environment Variables Best Practices: A Developer's Complete Guide
Master environment variables: how to use them correctly, avoid common security mistakes, manage secrets across environments, and implement .env best practices in any stack.
DevSecOps Tools Checklist 2026: 20 Essential Tools for Shift-Left Security
Complete DevSecOps tools checklist for 2026. 20 essential SAST, DAST, SCA, secrets scanning, and container security tools with free/open-source options.
Zero-Trust Architecture Implementation Guide for Developers 2026
Practical zero-trust architecture guide for developers: identity verification, network segmentation, service mesh, mTLS, and step-by-step implementation roadmap.
Microservices vs Monolith in 2026: When to Choose What
The honest guide to choosing between microservices and monolithic architecture in 2026. Real tradeoffs, migration strategies, service mesh, event-driven patterns, and case studies from Netflix, Uber, and Shopify.
Complete Guide to HTTP Security Headers: CSP, HSTS, and Modern Browser Security 2026
Master HTTP security headers in 2026: Content-Security-Policy configuration, HSTS preloading, Permissions-Policy, COEP/COOP for cross-origin isolation, and real-world configs for nginx, Apache, and Next.js.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →