For years the reference for web server TLS settings was Mozilla's Server Side TLS guide and its SSL Configuration Generator. In 2026 both moved to TLSRef, a community working group project outside Mozilla: the old generator's repository is archived and ssl-config.mozilla.org now redirects to configurator.tlsref.org. The recommendations themselves continue, at version 6.0 dated 6 April 2026.
This guide applies the recommended Intermediate profile to Nginx and Apache on Debian, and points out the distribution-specific details that trip people up.
What the Intermediate profile says
From the Server-Side TLS guidelines, Intermediate is "recommended for almost all systems":
- Protocols: TLS 1.2 and TLS 1.3 only.
- TLS 1.2 ciphers: ECDHE with AES-GCM or ChaCha20-Poly1305 only, all forward secret. DHE ciphers were removed in version 5.8.
- Key exchange groups: X25519MLKEM768, X25519, prime256v1, secp384r1. The first is a hybrid post-quantum group, added in version 5.8.
- Certificates: ECDSA P-256 recommended, or RSA 2048; 90-day lifetime recommended.
- Cipher order: the client chooses.
- HSTS:
max-age=63072000(two years).
The Modern profile allows TLS 1.3 only. Version 6.0 removed the Old profile entirely.
The guidelines explain the choices: every cipher suite in the list is strong and forward secret, so the client is allowed to choose, since it knows best whether it has hardware-accelerated AES. ECDSA certificates are recommended over RSA partly for compatibility with some older Windows clients. DHE suites were dropped because they cost more CPU than ECDHE and are more exposed to resource-exhaustion attacks. If a legacy client still cannot connect with this profile, treat that as a reason to upgrade the client rather than to weaken the server for everyone.
Check your OpenSSL version first
X25519MLKEM768 needs OpenSSL 3.5 or later, and the configurator drops it when you enter an older version. Debian 13 (trixie) ships OpenSSL 3.5; Debian 12 (bookworm) and Ubuntu 24.04 ship OpenSSL 3.0, so leave it out there.
openssl version
nginx -v
apache2 -vNginx on Debian
Debian's own /etc/nginx/nginx.conf already sets ssl_protocols and ssl_prefer_server_ciphers in the http block. Setting them again in a file under conf.d makes Nginx reject the configuration as a duplicate, so edit those two lines in place and add only the other directives in a separate file.
On Debian 13 the shipped values (ssl_protocols TLSv1.2 TLSv1.3; and ssl_prefer_server_ciphers off;) already match Intermediate. On Debian 12 the file enables TLS 1.0 and 1.1 and server cipher preference, so change those two lines to the Debian 13 values.
Then create /etc/nginx/conf.d/tls-intermediate.conf (included inside the http block) for Debian 13:
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;
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_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;On Debian 12 use ssl_ecdh_curve X25519:prime256v1:secp384r1; and add ssl_session_tickets off;, which the configurator emits for Nginx versions before 1.23.2 (Debian 12 ships 1.22.1).
The site's server blocks then look like this (Debian 13; on Debian 12 write listen 443 ssl http2; instead of the separate http2 on;):
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
return 308 https://$host$request_uri;
}Test and reload: sudo nginx -t && sudo systemctl reload nginx.
Apache on Debian
Enable the modules the configuration uses, then put the global settings in their own file so they override the defaults in mods-available/ssl.conf:
sudo a2enmod ssl headers rewrite http2Create /etc/apache2/conf-available/tls-intermediate.conf (Debian 13; on Debian 12 drop X25519MLKEM768: from the Curves line):
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLOpenSSLConfCmd Curves X25519MLKEM768:X25519:prime256v1:secp384r1
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
SSLCipherSuite TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder off
SSLSessionTickets offIn the HTTPS virtual host add Protocols h2 http/1.1 and Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains", and in the port 80 virtual host redirect to HTTPS while leaving ACME challenges reachable:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]Enable and reload: sudo a2enconf tls-intermediate && sudo apachectl configtest && sudo systemctl reload apache2.
About OCSP stapling
The configurator still offers OCSP stapling, but Let's Encrypt switched off its OCSP service in August 2025 and its certificates no longer contain an OCSP URL, so stapling does nothing for them. Leave it off unless your certificate comes from a CA that still runs OCSP.
Testing
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
openssl s_client -connect example.com:443 -servername example.com -tls1_2 -brief </dev/nullBoth should connect and report the protocol and cipher. Repeat from an older client you need to support. Include HSTS only once HTTPS works on every name the header covers: includeSubDomains applies to all subdomains for two years.
What you should do
- Bookmark configurator.tlsref.org; links to the Mozilla generator now redirect there.
- Use the Intermediate profile unless you control every client and can go TLS 1.3 only.
- Match the post-quantum group to your OpenSSL version: include X25519MLKEM768 only on OpenSSL 3.5 or later.
- On Debian, edit the existing
ssl_protocolslines innginx.confinstead of duplicating them. - Test with
nginx -torapachectl configtestbefore reloading, then from the outside withopenssl s_client.
Sources
- tlsref.org
- docs.tlsref.org/server-side-tls.html
- data.tlsref.org/guidelines/CHANGELOG.md
- configurator.tlsref.org
- github.com/tlsref/configurator
- github.com/mozilla/ssl-config-generator
- packages.debian.org/trixie/openssl
- packages.debian.org/bookworm/openssl
- packages.ubuntu.com/noble/openssl
- packages.debian.org/bookworm/nginx
- packages.debian.org/trixie/nginx
- sources.debian.org/src/nginx/1.26.3-3%2Bdeb13u10/debian/conf/nginx.conf
- sources.debian.org/src/nginx/1.22.1-9%2Bdeb12u9/debian/conf/nginx.conf
- letsencrypt.org/2025/08/06/ocsp-service-has-reached-end-of-life
- manpages.debian.org/trixie/openssl/openssl-s_client.1ssl.en.html
Comments
0 total · 0 threads