Why TLS Configuration Matters
A weak TLS configuration can expose your users to serious attacks even when using HTTPS. Outdated protocols and cipher suites allow:
- BEAST, POODLE, CRIME - Attacks on TLS 1.0 and older protocols
- DROWN - Attack exploiting SSLv2 support
- Logjam - Weak Diffie-Hellman parameters
- Sweet32 - Birthday attacks on 64-bit block ciphers
- Man-in-the-Middle - Decryption of traffic using weak ciphers
Protocol Version Guide
| Protocol | Status | Recommendation |
|---|---|---|
| SSLv2 | Broken | Never enable - DROWN attack |
| SSLv3 | Broken | Never enable - POODLE attack |
| TLS 1.0 | Deprecated | Disable - BEAST, multiple vulnerabilities |
| TLS 1.1 | Deprecated | Disable - No longer considered secure |
| TLS 1.2 | Secure | Enable with strong ciphers only |
| TLS 1.3 | Recommended | Enable - Fastest and most secure |
Modern Secure Configuration
Here's a production-ready TLS configuration for 2025:
# Modern TLS configuration (2025)
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Session handling
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
TLS 1.3 Only (Maximum Security)
If you can drop TLS 1.2 support (most modern clients support 1.3):
# TLS 1.3 only - maximum security
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# TLS 1.3 has built-in secure ciphers
# No need to specify ssl_ciphers
Insecure Patterns to Avoid
Outdated Protocols
# NEVER use these protocols
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1;
# These are vulnerable to POODLE, BEAST, and other attacks
Weak Cipher Suites
# NEVER use these ciphers
ssl_ciphers RC4:DES:3DES:MD5:EXPORT:NULL:ADH;
# RC4 - Broken stream cipher
# DES/3DES - Weak block ciphers (Sweet32)
# MD5 - Broken hash function
# EXPORT - Intentionally weak ciphers
# NULL - No encryption!
# ADH - No authentication
Certificate Configuration
server {
listen 443 ssl http2;
server_name example.com;
# Certificate and private key
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Trusted CA certificates for OCSP stapling
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Diffie-Hellman parameters (for TLS 1.2)
ssl_dhparam /etc/nginx/dhparam.pem;
# ... rest of configuration
}
Generate Strong DH Parameters
# Generate 4096-bit DH parameters (recommended)
openssl dhparam -out /etc/nginx/dhparam.pem 4096
# This takes several minutes but only needs to be done once
DH Parameter Warning
Weak or default DH parameters make your server vulnerable to the Logjam attack. Always generate your own 2048-bit or larger parameters.
OCSP Stapling
OCSP Stapling improves performance and privacy by having your server fetch certificate revocation status instead of the client.
# Enable OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# Trusted CA for OCSP verification
ssl_trusted_certificate /path/to/chain.pem;
# DNS resolver for OCSP responder
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
HTTP/2 and HTTP/3
# Enable HTTP/2
listen 443 ssl http2;
# Enable HTTP/3 (QUIC) - NGINX 1.25+
listen 443 quic reuseport;
listen 443 ssl;
# Advertise HTTP/3 support
add_header Alt-Svc 'h3=":443"; ma=86400';
Complete Server Block Example
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
# Certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Protocols and ciphers
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# DH parameters
ssl_dhparam /etc/nginx/dhparam.pem;
# Session handling
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
root /var/www/example.com;
index index.html;
}
Detecting Issues with Gixy
Gixy automatically detects weak SSL/TLS configurations:
$ gixy /etc/nginx/nginx.conf
==================== Results ====================
[weak_ssl_tls] Weak SSL/TLS configuration detected.
Severity: HIGH
Description: Outdated TLS protocols (TLSv1.0, TLSv1.1) or weak
cipher suites expose your server to attacks.
Reason: Protocol TLSv1 is deprecated and vulnerable.
File: /etc/nginx/conf.d/ssl.conf
Line: 5
==================== Summary ====================
Total issues: 1 (High: 1)
Testing Your Configuration
# Test with OpenSSL
openssl s_client -connect example.com:443 -tls1_3
# Check supported protocols
nmap --script ssl-enum-ciphers -p 443 example.com
# Online testing tools:
# - ssllabs.com/ssltest/
# - testssl.sh
SSL/TLS Checklist
- Disable SSLv2, SSLv3, TLS 1.0, and TLS 1.1
- Enable TLS 1.2 and TLS 1.3
- Use only AEAD cipher suites (GCM, ChaCha20-Poly1305)
- Generate 4096-bit DH parameters
- Enable OCSP Stapling
- Configure HSTS header
- Set up automatic certificate renewal
- Test with SSL Labs (aim for A+ grade)