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.

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, TLS 1.2
  • Disable: TLS 1.1, TLS 1.0, SSL 3.0, SSL 2.0

Nginx Configuration

ssl_protocols TLSv1.2 TLSv1.3;

Apache Configuration

SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1

2. Configure Strong Cipher Suites

Choose cipher suites that provide:

  • Forward secrecy (ECDHE or DHE key exchange)
  • Authenticated encryption (GCM or ChaCha20-Poly1305)
  • Strong hashing (SHA-256 or SHA-384)

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

  • RSA: Minimum 2048-bit (4096-bit for high security)
  • ECDSA: 256-bit (P-256 curve) or higher
  • Generate new keys when renewing certificates (don't reuse)

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

6. 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.

7. 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

8. 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;

9. 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
}

10. 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
  • OCSP stapling enabled
  • Complete certificate chain installed
  • Automated certificate monitoring in place

Related Articles