Controlling TLS cipher suites in Apache reduces exposure to weak cryptography, helps meet compliance baselines, and makes scanner results consistent across environments.
HTTPS in Apache is provided by mod_ssl, which uses OpenSSL to negotiate a protocol version and cipher suite during the TLS handshake. SSLCipherSuite controls the cipher list for TLS 1.2 and earlier, while TLS 1.3 cipher suites are configured separately through SSLOpenSSLConfCmd Ciphersuites when the OpenSSL build supports it.
Cipher hardening is safest when applied at the TLS virtual host level (inside `<VirtualHost *:443>`) and rolled out with syntax checks plus live negotiation tests. A too-strict policy can block legacy clients and upstream proxies, and a syntax error can prevent the apache2 service from reloading, so a rollback path and console access reduce the impact of accidental lockouts.
Related: How to test your Apache configuration
Related: How to enable or disable Apache modules
Steps to configure TLS ciphers in Apache:
- Show the active virtual host file that serves HTTPS on port 443.
$ sudo apache2ctl -S VirtualHost configuration: *:80 is a NameVirtualHost default server example.com (/etc/apache2/sites-enabled/000-default.conf:1) *:443 is a NameVirtualHost default server example.com (/etc/apache2/sites-enabled/default-ssl.conf:2) ##### snipped #####On RHEL-family systems, use apachectl -S and expect paths under /etc/httpd/.
- List the cipher names supported by the local OpenSSL build to avoid typos in SSLCipherSuite.
$ openssl ciphers -v 'ECDHE:!aNULL:!eNULL:!MD5:!3DES' 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 ##### snipped #####
SSLCipherSuite uses OpenSSL cipher string syntax, including colon-separated lists and selection rules.
- Add the TLS protocol and cipher policy directives inside the `<VirtualHost *:443>` block for the HTTPS site.
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName example.com SSLEngine On SSLProtocol -all +TLSv1.2 +TLSv1.3 SSLHonorCipherOrder On SSLCipherSuite 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 SSLOpenSSLConfCmd Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem </VirtualHost> </IfModule>Disabling TLS 1.0/1.1 or removing older cipher families can break legacy clients, older JVMs, and some upstream devices.
If apache2ctl -t reports an unknown protocol for TLSv1.3, remove +TLSv1.3 and keep only +TLSv1.2 for that host.
SSLOpenSSLConfCmd Ciphersuites is ignored on builds without TLS 1.3 support, and SSLCipherSuite does not affect TLS 1.3.
An “Invalid command 'SSLCipherSuite'” error usually indicates mod_ssl is not loaded.
Global defaults can be set in /etc/apache2/mods-available/ssl.conf when consistent policy across sites is preferred.
- Validate the Apache configuration syntax.
$ sudo apache2ctl -t Syntax OK
No output other than Syntax OK indicates the configuration is parseable.
- Reload apache2 to apply the new cipher policy.
$ sudo systemctl reload apache2
Use a reload for config-only changes, since existing connections typically remain established.
- Confirm a TLS 1.2 handshake negotiates an allowed cipher suite.
$ echo | openssl s_client -connect example.com:443 -servername example.com -tls1_2 CONNECTED(00000003) ##### snipped ##### SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 ##### snipped ##### - Confirm a TLS 1.3 handshake negotiates a cipher suite from Ciphersuites.
$ echo | openssl s_client -connect example.com:443 -servername example.com -tls1_3 CONNECTED(00000003) ##### snipped ##### SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 ##### snipped ##### - Enumerate offered ciphers from another host to verify ordering and protocol coverage.
$ nmap --script ssl-enum-ciphers -p 443 example.com Starting Nmap 7.94 ( https://nmap.org ) at 2025-12-13 20:15 UTC Nmap scan report for example.com (203.0.113.10) PORT STATE SERVICE 443/tcp open https | ssl-enum-ciphers: | TLSv1.2: | ciphers: | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A | cipher preference: server | TLSv1.3: | ciphers: | TLS_AES_256_GCM_SHA384 (ecdh_x25519) - A | TLS_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A | TLS_AES_128_GCM_SHA256 (ecdh_x25519) - A |_ least strength: A
The cipher preference: server line confirms SSLHonorCipherOrder On is being honored for TLS 1.2.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
Comment anonymously. Login not required.
