SSL/TLS Best Practices: Your Complete Security Guide
Follow these best practices to achieve an A+ security grade and protect your users from common attacks. This guide covers the most important SSL/TLS configurations.
The Hardening Path
The detailed sections below walk through every setting. At a high level, hardening a server follows five moves:
Lock down protocols
Serve only TLS 1.2 and TLS 1.3; disable everything older.
Pick strong ciphers
Restrict to AEAD suites with ECDHE forward secrecy.
Use solid keys & certs
2048-bit+ RSA or 256-bit+ ECDSA, with the full chain installed.
Add policy controls
Enable HSTS, publish a CAA record, and set security headers.
Test & monitor
Scan after every change and watch for expiry and drift.
1. Use Modern TLS Versions Only
Older SSL/TLS versions have known vulnerabilities. Configure your server to use only secure versions:
- TLS 1.3 — fastest and most secure.
- TLS 1.2 — acceptable with strong ciphers.
- TLS 1.1 and TLS 1.0 — deprecated by RFC 8996.
- SSL 3.0 and SSL 2.0 — broken; never serve them.
Nginx Configuration
ssl_protocols TLSv1.2 TLSv1.3;
Apache Configuration
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
X25519MLKEM768 (RFC 9794 / draft-kwiatkowski-tls-ecdhe-mlkem),
combining classical X25519 with NIST-standardised ML-KEM (FIPS 203). It's enabled by default
in Chrome 131+, Edge, Firefox 132+, and recent BoringSSL/OpenSSL builds. Keep your TLS library
up to date so clients negotiating PQC hybrid don't fall back to classical-only.
2. Configure Strong Cipher Suites
Choose cipher suites that provide all three of these properties:
Forward secrecy
ECDHE or DHE key exchange, so past traffic stays safe even if the key later leaks.
Authenticated encryption
AEAD ciphers — AES-GCM or ChaCha20-Poly1305 — for confidentiality and integrity together.
Strong hashing
SHA-256 or SHA-384 for handshake and message authentication.
Recommended Cipher Suite (Nginx)
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;
3. Enable HSTS (HTTP Strict Transport Security)
HSTS tells browsers to always use HTTPS, preventing protocol downgrade attacks and cookie hijacking.
HSTS Header
# Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Key settings:
- max-age: Time in seconds (31536000 = 1 year minimum recommended)
- includeSubDomains: Apply to all subdomains
- preload: Request inclusion in browser preload lists
4. Use Strong Keys and Certificates
Key Requirements
- Use 2048-bit+ RSA (4096-bit for high security).
- Or 256-bit+ ECDSA on the P-256 curve or higher.
- Generate a fresh key on every renewal.
- Reuse the same private key across renewals or hosts.
- Ship 1024-bit RSA keys — they're well below modern strength.
Certificate Best Practices
- Use certificates from trusted Certificate Authorities
- Include all hostnames and subdomains in the certificate (SAN)
- Keep certificate chains complete (include intermediate certificates)
- Monitor expiration dates and renew before expiry
5. Publish a CAA Record
A Certification Authority Authorization (CAA) DNS record tells CAs which issuers are allowed to mint certificates for your domain. Every publicly-trusted CA is required to check it before issuance (Baseline Requirements §3.2.2.8). It's a cheap, high-leverage control against mis-issuance and rogue insider attacks.
Example CAA Records
example.com. IN CAA 0 issue "letsencrypt.org"
example.com. IN CAA 0 issuewild "letsencrypt.org"
example.com. IN CAA 0 iodef "mailto:security@example.com"
example.com. IN CAA 0 issue ";" ; deny all other issuers
Tips:
- Use
issuewildseparately to control wildcard issuance. - Add
iodefto receive notifications about violation attempts. - If you use multiple CAs (primary + fallback), list each one explicitly.
6. Enable OCSP Stapling
OCSP Stapling improves performance and privacy by letting your server provide certificate revocation status instead of clients querying the CA.
Nginx Configuration
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
7. Configure DH Parameters (For DHE)
If using DHE cipher suites, generate strong custom DH parameters:
# Generate 2048-bit DH parameters (may take a while)
openssl dhparam -out /etc/ssl/dhparams.pem 2048
# Nginx
ssl_dhparam /etc/ssl/dhparams.pem;
8. Session Security
Session Resumption
# Nginx - secure session settings
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off; # Disable tickets for forward secrecy
9. Security Headers
Beyond HSTS, add these security headers:
# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline';" always;
# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
10. Complete Nginx SSL Configuration
Here's a complete, secure Nginx SSL configuration:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# Certificate files
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# Protocols
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suites
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;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# Session settings
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
# ... rest of configuration
}
11. Test Your Configuration
After making changes, test your server's SSL configuration:
Quick Reference Checklist
- TLS 1.2/1.3 only (disable older versions)
- Strong cipher suites with forward secrecy
- HSTS enabled with 1 year max-age
- 2048-bit+ RSA or 256-bit+ ECDSA keys
- CAA record published (restrict allowed CAs)
- OCSP stapling enabled
- Complete certificate chain installed
- Automated certificate monitoring in place