Back to Blog
January 5, 2026
GuardSSL Team

Cipher Suites Security Guide: TLS 1.2 to TLS 1.3 Configuration

Cipher Suites Security Guide: TLS 1.2 to TLS 1.3 Configuration

Your cipher suite configuration is the backbone of your website's encryption security. Get it wrong, and you're vulnerable to attacks. Get it right, and you earn user trust and better SEO rankings.

This guide walks you through secure cipher suite configuration for every major platform, with ready-to-use configuration snippets and troubleshooting tips.

Understanding Cipher Suite Security

What Makes a Cipher Suite Secure?

A secure cipher suite must provide:

  1. Forward Secrecy (FS): Sessions can't be decrypted later even if the private key is compromised
  2. Strong Encryption: At minimum AES-128 or ChaCha20
  3. Authenticated Encryption: Uses GCM or ChaCha20-Poly1305 modes
  4. No Known Vulnerabilities: Avoids RC4, DES, MD5, SHA1

Security Tier Classification

TierCipher SuitesUse Case
A+TLS 1.3 only (5 suites)Maximum security, modern clients
ATLS 1.3 + TLS 1.2 (5-8 suites)Best compatibility + security
BTLS 1.2 with legacy ciphersLegacy browser support needed
CIncludes weak ciphersNeeds urgent upgrade

TLS 1.3 Cipher Suites (Required for A+)

TLS 1.3 dramatically simplified cipher suite configuration. Only 5 suites are approved, and all are secure:

TLS 1.3 Cipher Suites

# TLS 1.3 only cipher suites (all secure, no configuration needed)
TLS_AES_256_GCM_SHA384      # AES-256-GCM with SHA-384
TLS_AES_128_GCM_SHA256      # AES-128-GCM with SHA-256 (recommended for performance)
TLS_CHACHA20_POLYPOLY1305_SHA256  # ChaCha20-Poly1305 (best for mobile)
TLS_AES_128_CCM_SHA256      # AES-128-CCM (IoT, low-power devices)
TLS_AES_128_CCM_8_SHA256    # AES-128-CCM-8 (very constrained devices)

Key point: TLS 1.3 cipher suites are non-negotiable—all 5 are secure. You don't need to manually configure them.

TLS 1.2 Cipher Suites (For Compatibility)

TLS 1.2 allows many cipher suites, including some that are insecure. You must carefully curate which ones to enable.

Priority 1: Modern, Forward Secret (Use These)

ECDHE-ECDSA-AES256-GCM-SHA384    # ECDHE forward secrecy, AES-256-GCM
ECDHE-ECDSA-AES128-GCM-SHA256    # ECDHE forward secrecy, AES-128-GCM (faster)
ECDHE-RSA-AES256-GCM-SHA384      # ECDHE forward secrecy, RSA auth, AES-256-GCM
ECDHE-RSA-AES128-GCM-SHA256      # ECDHE forward secrecy, RSA auth, AES-128-GCM
ECDHE-ECDSA-CHACHA20-POLY1305    # ECDHE forward secrecy, ChaCha20 (mobile)
ECDHE-RSA-CHACHA20-POLY1305      # ECDHE forward secrecy, RSA auth, ChaCha20

Priority 2: Legacy Compatibility (Optional)

ECDHE-ECDSA-AES256-SHA384        # CBC mode, SHA-384 (older systems)
ECDHE-ECDSA-AES128-SHA256        # CBC mode, SHA-256 (older systems)
ECDHE-RSA-AES256-SHA384          # CBC mode, SHA-384 (older systems)
ECDHE-RSA-AES128-SHA256          # CBC mode, SHA-256 (older systems)

Cipher Suites to Disable

Critical: Must Be Disabled

Cipher SuiteReason
aNULLNo authentication
eNULLNo encryption
EXPORTIntentionally weak (export compliance)
RC4Broken cipher
DES56-bit key (too weak)
3DES64-bit effective (slow and weak)
MD5Collision attacks
SHA1Collision attacks

Should Be Disabled (Deprecated)

Cipher SuiteReason
CBC without GCMBEAST attack risk
AES128-SHANo forward secrecy
AES256-SHANo forward secrecy
DHE-RSA-AES128-SHAWeak DH parameters

Nginx Configuration

Production-Ready Nginx Configuration

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com;

    # Certificate files
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # TLS Configuration - Modern
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Cipher suites - TLS 1.3 (auto) + TLS 1.2 (curated)
    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';
    
    # Prefer server cipher order
    ssl_prefer_server_ciphers on;
    
    # ECDH curve for key exchange
    ssl_ecdh_curve secp384r1;
    
    # Session cache
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # Security Headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # HSTS preload (submit to hstspreload.org)
}

# HTTP to HTTPS redirect
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com;
    return 301 https://$host$request_uri;
}

Test Your Nginx Configuration

# Test configuration syntax
nginx -t

# Reload configuration
nginx -s reload

# Check which ciphers your server offers
openssl s_client -connect yourdomain.com:443 -cipher 'ECDHE-RSA-AES128-GCM-SHA256' < /dev/null

# Full cipher scan
nmap --script ssl-enum-ciphers -p 443 yourdomain.com

Apache Configuration

Production-Ready Apache Configuration

<VirtualHost *:443>
    ServerName yourdomain.com
    DocumentRoot /var/www/html

    # Certificate files
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

    # TLS Configuration
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    
    # Cipher suites
    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 on
    
    # ECDH curve
    SSLECDHCurve secp384r1

    # Session cache
    SSLUseStapling on
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off

    # Security Headers
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</VirtualHost>

# HTTP to HTTPS redirect
<VirtualHost *:80>
    ServerName yourdomain.com
    Redirect permanent / https://yourdomain.com/
</VirtualHost>

Test Apache Configuration

# Test configuration
apachectl configtest

# Reload Apache
systemctl reload apache2

# Check cipher support
openssl s_client -connect yourdomain.com:443 < /dev/null 2>&1 | grep -i cipher

Cloud Platform Configuration

AWS Application Load Balancer (ALB)

# AWS CLI command to update ALB security policy
aws elbv2 modify-listener \
    --listener-arn arn:aws:elasticloadbalancing:region:account:listener/app/youralb/123 \
    --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 \
    --certificates CertificateArn=arn:aws:acm:region:account:certificate/id

Available TLS policies (AWS):

PolicyTLS 1.3TLS 1.2Notes
ELBSecurityPolicy-TLS13-1-2-2021-06Recommended
ELBSecurityPolicy-TLS13-1-1-2021-06Legacy compatibility
ELBSecurityPolicy-TLS13-1-0-2021-06Older clients
ELBSecurityPolicy-2016-08Legacy (avoid)

Cloudflare

// Cloudflare SSL/TLS Settings -> Edge Certificates
// TLS versions: TLS 1.2 + TLS 1.3
// Minimum TLS version: TLS 1.2

// Cipher suites (automatic, but you can enable "TLS 1.3 Only")
// No manual configuration needed - Cloudflare handles this

Cloudflare recommended settings:

SettingValue
TLS versionsTLS 1.2, TLS 1.3
Minimum TLS versionTLS 1.2
TLS 1.3Enabled
Automatic HTTPS RewritesOn
HSTSEnabled (max-age: 12 months)

Google Cloud Load Balancing

# gcloud compute ssl-policies create secure-tls-policy \
#     --description "TLS 1.3 with strong cipher suites" \
#     --min-tls-version 1.2 \
#     --profile Modern

# Available profiles:
# - Modern: TLS 1.2-1.3, strong ciphers
# - Intermediate: TLS 1.0-1.3, more compatibility
# - Legacy: All TLS versions, weak ciphers (avoid)

Microsoft Azure

# Set-AzApplicationGatewaySslPolicy -PolicyType Predefined -PolicyName AppGwSslPolicy20220101S

Recommended Azure policies:

Policy NameTLS 1.3TLS 1.2Notes
AppGwSslPolicy20220101SRecommended
AppGwSslPolicy20220101Legacy
ELBSecurityPolicy-TLS12-1-2-2021-06If using Azure Front Door

Testing Your Configuration

Quick Test Commands

# Test TLS 1.3 support
echo | openssl s_client -connect yourdomain.com:443 -tls1_3 2>&1 | grep "Protocol\|Cipher"

# Test TLS 1.2 support
echo | openssl s_client -connect yourdomain.com:443 -tls1_2 2>&1 | grep "Protocol\|Cipher"

# Check for weak ciphers
openssl s_client -connect yourdomain.com:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep -A 3 "Signature Algorithm"

# Test with SSL Labs (comprehensive)
# https://www.ssllabs.com/ssltest/analyze.html?d=yourdomain.com

SSL Labs Grading Criteria (2026)

GradeRequirements
A+TLS 1.3, HSTS preload, no vulnerabilities, 100% key exchange, 90%+ encryption
ATLS 1.3, no vulnerabilities, 80%+ key exchange, 80%+ encryption
BTLS 1.2+, minor issues, 60%+ key exchange
CTLS 1.2, some weak ciphers
D-FTLS 1.0/1.1, weak ciphers, vulnerabilities

Common SSL Labs Warnings

WarningCauseFix
"Chain issues"Missing intermediate certInstall full certificate chain
"Strict Transport Security"HSTS not enabledAdd HSTS header
"Secure Client-Initiated Renegotiation"Renegotiation allowedDisable with ssl_renegotiate
"Logjam"Weak DH parametersUse ECDH with secp384r1 or higher
"Sweet32"3DES cipher enabledRemove 3DES from cipher list

Troubleshooting Common Issues

Issue: Grade Dropped After Update

Symptom: Your SSL grade dropped from A to B after updating configuration.

Common causes:

  1. Removed CBC mode ciphers but server can't negotiate with some clients
  2. ECDH curve too high (secp521r1 not supported by all clients)
  3. Missing RSA key exchange ciphers for compatibility

Solution: Use secp384r1 for ECDH, keep 4-6 modern cipher suites.

Issue: Some Clients Can't Connect

Symptom: Older browsers or devices fail to connect.

Solution: Check what's failing:

# Test with specific cipher
openssl s_client -connect yourdomain.com:443 -cipher 'ECDHE-RSA-AES128-SHA' < /dev/null

# Add fallback cipher if needed
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';

Issue: OCSP Stapling Not Working

Symptom: SSL Labs reports "OCSP stapling: No"

Solution:

# Verify OCSP is enabled
ssl_stapling on;
ssl_stapling_verify on;

# Check DNS resolver
resolver 8.8.8.8 8.8.4.4 valid=300s;

# Test OCSP response
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -status < /dev/null

Issue: Mixed Content Warnings

Symptom: HTTPS page loads HTTP resources.

Solution:

# Force HTTPS and fix mixed content
add_header Content-Security-Policy "upgrade-insecure-requests" always;

Automated Monitoring

Cipher Suite Health Check Script

#!/bin/bash
# ssl-health-check.sh

DOMAIN="yourdomain.com"
ALERT_EMAIL="[email protected]"

# Get SSL grade from SSL Labs API (simplified)
GRADE=$(curl -s "https://api.ssllabs.com/api/v3/analyze/${DOMAIN}" | jq -r '.endpoints[0].grade')

if [[ "$GRADE" == "A" || "$GRADE" == "A+" ]]; then
    echo "SSL Grade: $GRADE ✓"
    exit 0
else
    echo "WARNING: SSL Grade is $GRADE (expected A or A+)" | mail -s "SSL Alert: $DOMAIN" $ALERT_EMAIL
    exit 1
fi

Add to Cron

# Run daily health check
0 9 * * * /usr/local/bin/ssl-health-check.sh

Configuration Checklist

Before Deployment

  • Backup current configuration
  • Test in staging environment
  • Verify TLS 1.3 works (openssl s_client)
  • Verify TLS 1.2 fallback works
  • Check SSL Labs grade
  • Verify all subdomains work

After Deployment

  • Test from multiple networks
  • Verify mobile device connectivity
  • Check server error logs for SSL errors
  • Monitor for any connection failures
  • Update monitoring alerts if needed

Ongoing Maintenance

  • Review SSL Labs report weekly
  • Update cipher lists quarterly
  • Monitor TLS version usage
  • Test new cipher suites before enabling
  • Keep up with TLS 1.4 (when released)

TL;DR Quick Reference

Nginx One-Liner (TLS 1.2 + 1.3)

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';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;

Apache One-Liner (TLS 1.2 + 1.3)

SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on
SSLECDHCurve secp384r1

Golden Rules

  1. Always use TLS 1.3 when possible
  2. Enable TLS 1.2 for compatibility
  3. Disable TLS 1.0 and 1.1 (insecure)
  4. Disable SSL 2.0 and 3.0 (obsolete)
  5. Prefer GCM and ChaCha20 over CBC
  6. Use forward secrecy (ECDHE)
  7. Test with SSL Labs after any changes

Monitor Your Security

Proper configuration is just the beginning. Monitor your certificates and configuration continuously.

Check your cipher suite configuration with GuardSSL →

Instant analysis of your TLS setup, cipher suites, and security recommendations. Free and takes less than 5 seconds.

This guide was updated January 2026 to reflect the latest TLS standards and security best practices.

Check Your SSL Certificate Now

Want to see these certificate details for your own website? Use our free SSL checker to instantly analyze your certificate's security, validity, and configuration.

No registration required • Instant results • 100% free