Configuring the TLS cipher policy in Apache limits which encryption suites clients can negotiate, which helps remove weak legacy choices, align HTTPS endpoints with current scanner baselines, and make certificate and proxy rollouts more predictable.
HTTPS in Apache is handled by mod_ssl on top of OpenSSL. On current Apache HTTP Server 2.4 builds, SSLCipherSuite can set the cipher list for TLS 1.2 and earlier and, when Apache is linked against OpenSSL 1.1.1 or later, a separate SSLCipherSuite TLSv1.3 … line can set the TLS 1.3 suites directly.
Examples below use the Debian and Ubuntu layout with /etc/apache2/, the apache2 systemd unit, and the apache2ctl wrapper. RHEL-family systems usually use /etc/httpd/ plus apachectl or httpd instead. Restricting protocols or ciphers can block older clients and upstream devices, and the negotiated suite still depends on the server certificate type, so syntax tests plus live TLS handshakes are part of the change.
Related: How to test Apache configuration
Related: How to enable or disable Apache modules
$ sudo apache2ctl -S VirtualHost configuration: *:443 host.example.net (/etc/apache2/sites-enabled/host.example.net.conf:1) ServerRoot: "/etc/apache2" Main DocumentRoot: "/var/www/html" Main ErrorLog: "/var/log/apache2/error.log" Mutex ssl-stapling-refresh: using_defaults Mutex ssl-stapling: using_defaults Mutex ssl-cache: using_defaults Mutex default: dir="/var/run/apache2/" mechanism=default PidFile: "/var/run/apache2/apache2.pid" ##### snipped #####
Use sudo apachectl -S or sudo httpd -S on platforms that do not ship apache2ctl.
$ openssl ciphers -s -v -tls1_2 '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' ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
The -tls1_2 filter keeps this check aligned with the SSLCipherSuite SSL … line used later. TLS 1.3 uses separate suite names.
The negotiated TLS 1.2 suite must match the server certificate type. A host using an RSA certificate will negotiate the RSA entries from the list, not the ECDSA entries.
$ sudo vi /etc/apache2/sites-available/host.example.net.conf
Global policy can live in /etc/apache2/mods-available/ssl.conf or the equivalent httpd SSL config when the same cipher rules must apply to every HTTPS virtual host.
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName host.example.net
SSLEngine On
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLHonorCipherOrder On
SSLCipherSuite SSL 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
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
</VirtualHost>
</IfModule>
Removing TLS 1.0 or TLS 1.1 support and narrowing the cipher list can break older browsers, older Java runtimes, load balancers, or API clients.
If apache2ctl configtest reports an unknown protocol or rejects the TLS 1.3 line, remove +TLSv1.3 and the SSLCipherSuite TLSv1.3 … directive and keep the TLS 1.2 policy only.
Current Apache 2.4 builds can configure TLS 1.3 suites directly with SSLCipherSuite TLSv1.3 …. Older examples often use SSLOpenSSLConfCmd Ciphersuites instead.
An “Invalid command 'SSLCipherSuite'” error usually means mod_ssl is not loaded.
$ sudo apache2ctl configtest Syntax OK
sudo apache2ctl -t performs the same syntax check. Use sudo apachectl -t or sudo httpd -t on other platforms.
Related: How to test Apache configuration
$ sudo systemctl reload apache2
When systemd is not managing the service, use sudo apache2ctl graceful or the platform-equivalent reload command.
$ echo | openssl s_client -connect host.example.net:443 -servername host.example.net -tls1_2 2>/dev/null | sed -n '/New, /p;/Protocol :/p;/Cipher :/p'
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
With an RSA certificate, seeing an ECDHE-RSA-… suite here is expected even when ECDSA suites appear earlier in the configured list.
$ echo | openssl s_client -connect host.example.net:443 -servername host.example.net -tls1_3 2>/dev/null | sed -n '/New, /p;/Protocol :/p;/Cipher :/p'
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Available TLS 1.3 suites are limited to the standard names exposed by the linked OpenSSL library.
$ nmap --script ssl-enum-ciphers -p 443 host.example.net Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-04-08 04:34 UTC Nmap scan report for host.example.net (192.0.2.40) Host is up (0.00017s latency). PORT STATE SERVICE 443/tcp open https | ssl-enum-ciphers: | TLSv1.2: | ciphers: | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A | compressors: | NULL | cipher preference: server | TLSv1.3: | ciphers: | TLS_AKE_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A | TLS_AKE_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A | TLS_AKE_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A | cipher preference: server |_ least strength: A
The cipher preference: server line confirms the server is choosing the preferred suite order for the negotiated set.
nmap uses TLS_AKE_WITH_* labels for TLS 1.3 suites, which correspond to the configured TLS_AES_* and TLS_CHACHA20_* names.