SSL Labs A+ Rating Configuration Guide

Achieving an A+ rating on SSL Labs demonstrates commitment to security best practices and strong TLS configuration. This guide provides templates and detailed configuration for obtaining perfect SSL Labs scores on Nginx and Apache.

Table of Contents

Prerequisites

Before pursuing an A+ rating, ensure you have:

  • Web server (Nginx 1.13+ or Apache 2.4.36+)
  • OpenSSL 1.1.1+ installed
  • Valid SSL certificate (ECC or RSA)
  • Root or sudo access
  • DNS control for testing

SSL Labs Grading Criteria

SSL Labs evaluates:

  1. Protocol Support (30%)

    • TLS versions enabled/disabled
    • Support for latest TLS 1.3
  2. Key Exchange (10%)

    • Key strength and size
    • Supported curves
    • Perfect forward secrecy
  3. Cipher Strength (40%)

    • Cipher suite strength
    • Symmetric algorithm strength
    • No weak ciphers
  4. Certificate Strength (20%)

    • Certificate type (ECC > RSA)
    • Key size
    • Signature algorithm

Scoring:

  • A+: 90-100 points (requires all A criteria + additional items)
  • A: 80-89 points
  • B: 70-79 points
  • C-F: Below 70 points (security issues)

Perfect Score Requirements

For A+ rating:

✓ TLS 1.3 enabled ✓ TLS 1.2 enabled ✓ No TLS 1.1, 1.0, or SSLv3 ✓ No RC4, MD5, or other weak ciphers ✓ HSTS header with preload ✓ Forward secrecy on all cipher suites ✓ Recommended: ECC certificate

Nginx A+ Configuration

Complete Nginx configuration for A+ rating:

# /etc/nginx/sites-available/example.com

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

# HTTPS server
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL Certificates (prefer ECC over RSA)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # Protocol configuration
    # TLS 1.3 and 1.2 only (A+ requirement)
    ssl_protocols TLSv1.3 TLSv1.2;
    
    # Cipher suite configuration (A+ requirement)
    # TLS 1.3 cipher suites
    ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256;
    
    # Fallback TLS 1.2 cipher suites (only strong ones)
    ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    
    # Prefer server order
    ssl_prefer_server_ciphers on;
    
    # Forward secrecy (ephemeral ECDH)
    ssl_ecdh_curve X25519:X448:secp384r1:secp256r1;
    
    # Session management
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_ticket_key /etc/nginx/ssl_ticket.key;
    
    # OCSP Stapling (A+ helper)
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_stapling_file /var/cache/nginx/ocsp.staple;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    
    # Resolver for OCSP
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # Root certificate trust
    root /var/www/example.com;
    index index.html index.htm;
    
    # Content Security Policy (recommended)
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" always;
    
    # HSTS header - CRITICAL for A+ rating
    # Include preload for HSTS Preload list
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    
    # Additional security headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
    # Location configuration
    location / {
        try_files $uri $uri/ =404;
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Apache A+ Configuration

Complete Apache configuration for A+ rating:

# /etc/apache2/sites-available/example.com.conf

# HTTP to HTTPS redirect
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

# HTTPS configuration
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    
    SSLEngine on
    
    # SSL Certificates (prefer ECC)
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
    
    # Protocol configuration (A+ requirement)
    SSLProtocol TLSv1.3 TLSv1.2
    
    # Cipher suite configuration (A+ requirement)
    SSLCipherSuite TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    
    # Server controls cipher order
    SSLHonorCipherOrder on
    
    # Forward secrecy with elliptic curves
    SSLOpenSSLConfCmd Curves X25519:X448:secp384r1:secp256r1
    
    # Session management
    SSLSessionCache shmcb:/var/run/apache2/ssl_scache(512000)
    SSLSessionCacheTimeout 300
    
    # OCSP Stapling (A+ helper)
    SSLUseStapling on
    SSLStaplingCache shmcb:/var/run/apache2/ocsp_cache(128000)
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off
    
    # DocumentRoot
    DocumentRoot /var/www/example.com
    
    <Directory /var/www/example.com>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    # Enable mod_headers for security headers
    <IfModule mod_headers.c>
        # HSTS header - CRITICAL for A+ rating
        # Include preload
        Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        
        # Additional security headers
        Header always set X-Content-Type-Options "nosniff"
        Header always set X-Frame-Options "DENY"
        Header always set X-XSS-Protection "1; mode=block"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
        Header always set Content-Security-Policy "default-src 'self'"
    </IfModule>
    
    # Logging
    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
</VirtualHost>

Enable required modules:

sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2enmod socache_shmcb
sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

Testing with SSL Labs

Test your configuration with SSL Labs.

Navigate to https://www.ssllabs.com/ssltest/analyze.html and enter your domain.

Rating scale:

  • A+ (90-100): Excellent
  • A (80-89): Very Good
  • B (70-79): Good
  • C (60-69): Acceptable
  • D (50-59): Poor
  • F (<50): Fail

What A+ requires:

  1. Certificate Quality: 100%

    • Valid certificate for domain
    • Trusted CA
    • Appropriate key size
  2. Protocol Support: 100%

    • TLS 1.3 enabled
    • TLS 1.2 enabled
    • No older protocols
  3. Key Exchange: 100%

    • All algorithms with forward secrecy
    • Strong key sizes
    • Supported curves
  4. Cipher Strength: 100%

    • All ciphers strong
    • 128-bit minimum for encryption
    • No deprecated algorithms
  5. HSTS: Required

    • max-age minimum 18 months
    • Preload flag for A+ boost

Automated testing with testssl.sh:

# Download testssl.sh
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
cd testssl.sh

# Run full test
./testssl.sh --full https://example.com

# Specific check
./testssl.sh --tlsv1_3 https://example.com

HSTS and Preload

HSTS (HTTP Strict Transport Security) is crucial for A+ rating.

HSTS header components:

max-age=63072000        # 2 years in seconds (minimum for preload)
includeSubDomains       # Apply to all subdomains
preload                 # Allow inclusion in preload list

Submit to HSTS Preload:

  1. Visit https://hstspreload.org/
  2. Enter domain
  3. Verify HSTS header meets requirements
  4. Submit for inclusion

Check if already preloaded:

curl -s https://hstspreload.org/api/v3/status?domain=example.com | jq .

Benefits of HSTS preload:

  • Browser never connects via HTTP
  • Prevents downgrade attacks
  • Improves security on first visit

Certificate Requirements

For A+ rating, choose certificate carefully:

ECC Certificates (preferred):

  • Smaller key sizes (256-bit equivalent to 3072-bit RSA)
  • Better performance
  • Future-proof

RSA Certificates (acceptable):

  • Minimum 2048-bit (older browsers)
  • Recommend 4096-bit for A+
  • Widely supported

Obtain ECC certificate from Let's Encrypt:

# Let's Encrypt uses RSA by default, but supports ECC
# Use with certbot to get ECDSA certificate
sudo certbot certonly \
  --server https://acme-v02.api.letsencrypt.org/directory \
  -d example.com \
  --key-type ecdsa \
  --elliptic-curve secp384r1

Check certificate type:

openssl x509 -in cert.pem -text -noout | grep "Public Key"

Troubleshooting

Common issues preventing A+ rating:

Protocol issues:

# Check enabled protocols
openssl s_client -tls1_2 -connect example.com:443
openssl s_client -tls1_3 -connect example.com:443

# Should succeed with TLS 1.2 and 1.3
# Should fail with older versions

Cipher suite issues:

# List enabled ciphers
openssl s_client -connect example.com:443 -cipher 'ALL' -tls1_2

HSTS issues:

# Check HSTS header
curl -i https://example.com | grep Strict-Transport

# Verify HSTS requirements
# max-age >= 18 months (63072000 seconds)
# includeSubDomains present
# preload flag present

Certificate issues:

# Check certificate chain
openssl x509 -in cert.pem -text -noout | grep -i "subject\|issuer"

# Verify certificate validity
openssl verify -CAfile chain.pem cert.pem

Maintenance

Maintain A+ rating:

Monitor certificate expiration:

# Check expiration date
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates

# Automated renewal with hooks
certbot renew --post-hook "systemctl reload nginx"

Regular SSL Labs testing:

# Schedule monthly testing
0 0 1 * * curl "https://api.ssllabs.com/api/v3/analyze?host=example.com&publish=off" > /dev/null 2>&1

Update cipher suites as needed:

# Review for new TLS 1.3 cipher suites
# Update configuration quarterly

Conclusion

Achieving an A+ SSL Labs rating demonstrates security excellence. This guide provided complete Nginx and Apache configurations meeting all A+ requirements. Key components include TLS 1.3 support, strong cipher suites, HSTS with preload, OCSP stapling, and ECC certificates. For production deployments, implement this configuration, test with SSL Labs, submit HSTS for preload, and maintain through regular monitoring and updates. An A+ rating provides users confidence in your security posture and demonstrates commitment to best practices.