Tools Learn Login Sign up
Home / Learn / SSL/TLS Best Practices

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.

Goal: By following these practices, your server should achieve an A or A+ grade on SSL Labs and similar security scanners.

The Hardening Path

The detailed sections below walk through every setting. At a high level, hardening a server follows five moves:

1

Lock down protocols

Serve only TLS 1.2 and TLS 1.3; disable everything older.

2

Pick strong ciphers

Restrict to AEAD suites with ECDHE forward secrecy.

3

Use solid keys & certs

2048-bit+ RSA or 256-bit+ ECDSA, with the full chain installed.

4

Add policy controls

Enable HSTS, publish a CAA record, and set security headers.

5

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:

Enable
  • TLS 1.3 — fastest and most secure.
  • TLS 1.2 — acceptable with strong ciphers.
Disable
  • 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
Looking forward: TLS 1.3 now widely supports the post-quantum hybrid key exchange 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;
TLS 1.3 Note: TLS 1.3 has a fixed set of secure cipher suites and doesn't require manual configuration - another reason to prefer it.

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
Caution: Before enabling HSTS, ensure HTTPS works correctly on all subdomains. Once enabled, browsers will refuse HTTP connections for the specified duration.

4. Use Strong Keys and Certificates

Key Requirements

Do
  • 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.
Don't
  • 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 issuewild separately to control wildcard issuance.
  • Add iodef to 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;
Better Option: Prefer ECDHE over DHE - it's faster and doesn't require DH parameter configuration.

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
}
Skip the Manual Config — Generate It
Our SSL Config Generator produces hardened Nginx, Apache, Caddy, and HAProxy configs with all the best practices above baked in. You can also paste your existing config to get it analyzed.
Open SSL Config Generator →

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

Related Articles

Report a bug

We're new and growing — your feedback helps us improve.

Click to upload, or paste (Ctrl+V) an image