Skip to content

Last updated: 2026-06-25

Apache TLS/SSL Configuration Guide

This guide provides recommended TLS/SSL settings for the Apache HTTP Server using mod_ssl. These settings are designed to achieve an A+ rating on Qualys SSL Labs while maintaining compatibility with modern clients.

Prerequisites

  • Apache 2.4.43 or later (for SSLCipherSuite TLSv1.3 syntax)
  • mod_ssl and mod_headers enabled
  • OpenSSL 1.1.1 or later
  • A valid SSL/TLS certificate from a trusted CA

Ensure the required modules are loaded:

LoadModule ssl_module modules/mod_ssl.so
LoadModule headers_module modules/mod_headers.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so

Protocol Versions

Disable all legacy protocols and allow only TLS 1.2 and TLS 1.3:

SSLProtocol -all +TLSv1.2 +TLSv1.3

Cipher Suites

Use only AEAD cipher suites with ECDHE key exchange for forward secrecy. Apache 2.4.43+ supports separate cipher configuration for TLS 1.2 and TLS 1.3:

SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256

Note: On Apache < 2.4.43, the SSLCipherSuite TLSv1.3 directive is not recognized. Omit it; OpenSSL's TLS 1.3 cipher defaults are strong and apply automatically.

Since all ciphers in the list are equally strong, server cipher order preference can be disabled:

SSLHonorCipherOrder off

Certificate Configuration

SSLCertificateFile      /etc/httpd/ssl/fullchain.pem
SSLCertificateKeyFile   /etc/httpd/ssl/privkey.pem

Use a full-chain certificate file that includes both the server certificate and intermediate CA certificates. The SSLCertificateChainFile directive was deprecated in Apache 2.4.8 and removed in later versions; SSLCertificateFile with a full-chain PEM replaces it.

On Debian/Ubuntu systems, paths are typically under /etc/apache2/ssl/ instead of /etc/httpd/ssl/.

Security Settings

Explicitly set SSL compression off (the default since 2.4.3, but worth stating) and disable session tickets for forward secrecy. Unlike nginx, Apache does not rotate session ticket keys automatically, so a static key persists until the next restart:

SSLCompression off
SSLSessionTickets off

OCSP Stapling

Enable OCSP stapling to improve TLS handshake performance and user privacy. The stapling cache must be configured in the global server context (outside of any VirtualHost):

SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
SSLStaplingResponseMaxAge 900

The logs/ path is relative to ServerRoot. On RHEL/CentOS (ServerRoot /etc/httpd) it resolves via a symlink to /var/log/httpd/. On Debian/Ubuntu (ServerRoot /etc/apache2), use an absolute path like "shmcb:/var/log/apache2/ssl_stapling(32768)" instead.

HTTP Strict Transport Security (HSTS)

Add the HSTS header to force browsers to use HTTPS for all future connections:

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

Only enable includeSubDomains if all subdomains support HTTPS. Only add preload if you intend to submit your domain to the HSTS preload list.

HTTPS Redirect

Redirect all HTTP traffic to HTTPS:

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

Complete Configuration Example

Global settings (in httpd.conf or ssl.conf):

SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

Virtual host configuration:

<VirtualHost *:443>
    ServerName example.com

    # Enable SSL
    SSLEngine on

    # Certificates (Debian/Ubuntu: /etc/apache2/ssl/)
    SSLCertificateFile      /etc/httpd/ssl/fullchain.pem
    SSLCertificateKeyFile   /etc/httpd/ssl/privkey.pem

    # Protocols and ciphers
    SSLProtocol -all +TLSv1.2 +TLSv1.3
    SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
    SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
    # Note: On Apache < 2.4.43, omit the SSLCipherSuite TLSv1.3 line;
    # OpenSSL's TLS 1.3 cipher defaults are strong and apply automatically.
    SSLHonorCipherOrder off

    # Security settings
    SSLCompression off
    SSLSessionTickets off

    # OCSP stapling
    SSLUseStapling on
    SSLStaplingResponseMaxAge 900

    # Security headers
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

    # ... your site configuration
</VirtualHost>

Mutual TLS (mTLS)

Standard TLS authenticates only the server: the client verifies the server's certificate, but the server does not verify the client. Mutual TLS adds client authentication, requiring the connecting client to also present a certificate. This is an optional hardening step, not required for standard web deployments. It is most useful for internal APIs, admin endpoints, and service-to-service communication where you control all connecting clients.

Add the following to your VirtualHost block to require client certificates:

SSLCACertificateFile /etc/httpd/ssl/client-ca.crt
SSLVerifyClient require
SSLVerifyDepth 2
  • SSLCACertificateFile - CA certificate used to verify client certificates.
  • SSLVerifyClient require - Require a valid client certificate. Connections without one are rejected.
  • SSLVerifyClient optional - Request a client certificate but allow connections without one. Use %{SSL_CLIENT_VERIFY}e in access logs or per-location checks to inspect the result.
  • SSLVerifyDepth - Maximum certificate chain depth. Set to 2 if client certs are issued by an intermediate CA.

To enforce mTLS on a specific path only:

<Location /api/>
    SSLVerifyClient require
    SSLCACertificateFile /etc/httpd/ssl/client-ca.crt
    SSLVerifyDepth 2
</Location>

The client certificate subject is available via the SSL_CLIENT_S_DN environment variable and can be forwarded to backend applications:

RequestHeader set X-SSL-Client-DN "%{SSL_CLIENT_S_DN}e"

See RFC 8446 ยง4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.

Security Notes

The cipher suite and protocol configuration in this guide addresses the following known TLS vulnerabilities:

  • POODLE (CVE-2014-3566, 2014): SSL 3.0 is disabled. TLS_FALLBACK_SCSV was added in OpenSSL 1.0.1j / 1.0.2 (October 2014); SSL 3.0 disabled by default in OpenSSL 1.1.0 (August 2016).
  • BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
  • CRIME (CVE-2012-4929, 2012): TLS compression is off by default in OpenSSL 1.1.0+; do not enable it.
  • Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
  • FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers are excluded from the cipher string. Removed from OpenSSL 1.1.0 (August 2016).
  • LOGJAM (CVE-2015-4000, 2015): Short-key DHE is excluded; only ECDHE key exchange is recommended.
  • Sweet32 (CVE-2016-2183, 2016): 3DES is excluded from the cipher string.
  • ROBOT (2017): Static RSA key exchange is excluded; only ECDHE is recommended.
  • Downgrade attacks: TLS_FALLBACK_SCSV prevents protocol version rollback.
  • Renegotiation injection (CVE-2009-3555, 2009): Secure renegotiation is enforced by default in OpenSSL 0.9.8m+; TLS 1.3 removes renegotiation entirely.

The following are not addressable through TLS configuration alone:

  • Heartbleed (CVE-2014-0160, 2014): A memory disclosure bug in OpenSSL 1.0.1 through 1.0.1f. Fixed in OpenSSL 1.0.1g (April 7, 2014). Addressed by patching OpenSSL, not by TLS configuration.
  • BREACH (CVE-2013-3587, 2013): Exploits HTTP-level response compression (gzip/deflate on responses). Mitigated at the application layer by disabling HTTP compression or using BREACH countermeasures; TLS configuration cannot prevent it.
  • DROWN (CVE-2016-0800, 2016): Requires SSLv2 to be enabled on any server sharing the same private key. Ensure SSLv2 is disabled on all services that use the same certificate and key pair.

Verification

Test your Apache configuration before restarting:

apachectl configtest
systemctl restart httpd

On Debian/Ubuntu:

apache2ctl configtest
systemctl restart apache2

Test your configuration externally with the Mr.DNS SSL/TLS Certificate Check.


Related Guides

View all Web Servers & Proxies guides →

Configured TLS? Now Monitor It.

Generator Labs alerts you before certificates expire, get revoked, or fail chain validation, across HTTPS, SMTPS, IMAPS, LDAPS, and more.

Certificate Monitoring →