When attempting to configure Nginx to use exclusively TLS 1.3 with specific cipher suites, many administrators encounter the following error:
nginx: [emerg] SSL_CTX_set_cipher_list("TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256") failed
(SSL: error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match)
The root cause lies in how OpenSSL handles TLS 1.3 cipher specification. Unlike TLS 1.2 and below, TLS 1.3 cipher suites cannot be configured through the traditional SSL_CTX_set_cipher_list()
interface. This creates a fundamental incompatibility when trying to specify TLS 1.3 ciphers exclusively.
There are two practical approaches to achieve TLS 1.3-only configuration:
Option 1: Minimum Required Configuration
Add a single TLS 1.2 cipher while disabling all TLS 1.2 protocols:
ssl_protocols TLSv1.3;
ssl_ciphers TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
This satisfies OpenSSL's API requirements while effectively enforcing TLS 1.3 in practice.
Option 2: OpenSSL 1.1.1+ Approach
For OpenSSL 1.1.1 and later, you can use cipher string directives:
ssl_protocols TLSv1.3;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;
ssl_ciphers HIGH:!aNULL:!MD5; # Dummy value to satisfy OpenSSL API
To confirm your configuration is working as intended:
openssl s_client -connect yourdomain.com:443 -tls1_3
Check the cipher suite output should only show your specified TLS 1.3 ciphers.
1. OpenSSL versions prior to 1.1.1 don't support TLS 1.3
2. The cipher suite names are case-sensitive in configuration
3. Always test with multiple TLS clients before deploying to production
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# TLS configuration
ssl_protocols TLSv1.3;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; # Dummy cipher required by OpenSSL API
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
}
When attempting to configure Nginx with only TLS 1.3 cipher suites, many administrators encounter an unexpected roadblock. The configuration seems straightforward:
ssl_protocols TLSv1.3;
ssl_ciphers TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256;
Yet this results in the frustrating error:
nginx: [emerg] SSL_CTX_set_cipher_list("TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256") failed (SSL: error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match)
The root cause lies in how OpenSSL handles cipher suite configuration. In versions prior to OpenSSL 1.1.1, the cipher suite configuration API wasn't fully adapted for TLS 1.3's different approach to cipher negotiation.
Key points:
- TLS 1.3 cipher suites are fundamentally different from TLS 1.2 suites
- OpenSSL's
SSL_CTX_set_cipher_list()
expects at least one non-TLS 1.3 cipher - The API was designed before TLS 1.3's finalization
Here are three approaches to achieve TLS 1.3-only security:
Solution 1: Minimum Viable Configuration
ssl_protocols TLSv1.3;
ssl_ciphers TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
This satisfies OpenSSL's requirement while effectively using only TLS 1.3 in practice (the TLS 1.2 cipher will never be selected).
Solution 2: OpenSSL 1.1.1+ Configuration
With newer OpenSSL versions (1.1.1+), you can use:
ssl_protocols TLSv1.3;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;
Solution 3: BoringSSL Alternative
If using BoringSSL (common in some distributions), this works:
ssl_protocols TLSv1.3;
ssl_ciphers [TLS_AES_256_GCM_SHA384|TLS_AES_128_GCM_SHA256];
After applying changes, verify with:
openssl s_client -connect yourdomain.com:443 -tls1_3
Or using testssl.sh:
testssl.sh -p yourdomain.com
When using only TLS 1.3:
- 0-RTT can improve performance for returning visitors
- Fewer handshake round trips (1-RTT vs 2-RTT in TLS 1.2)
- AES-GCM hardware acceleration is widely available