Short answer

A secure Apache TLS setup uses SSLCertificateFile with a fullchain file (or a separate SSLCertificateChainFile on older versions), sets SSLProtocol to TLSv1.2 and TLSv1.3 only, a short SSLCipherSuite with forward secrecy, enables OCSP stapling and HSTS. You reload with zero downtime using apachectl graceful.

The complete VirtualHost

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    SSLEngine on

    # Fullchain file (leaf + intermediates). On httpd < 2.4.8
    # use a separate SSLCertificateChainFile instead.
    SSLCertificateFile    /etc/ssl/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem

    # Modern protocols only
    SSLProtocol -all +TLSv1.2 +TLSv1.3

    # Strong ciphers with forward secrecy; let the server decide
    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
    SSLHonorCipherOrder on

    # HSTS
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</VirtualHost>

# OCSP stapling is configured globally (outside the VirtualHost)
SSLUseStapling on
SSLStaplingCache "shmcb:/var/run/ocsp(128000)"

# Redirect HTTP to HTTPS
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

The certificate chain: fullchain vs SSLCertificateChainFile

From httpd 2.4.8, SSLCertificateFile can contain the whole chain (leaf + intermediates) in one file — use fullchain.pem. On older versions you must supply intermediates separately with SSLCertificateChainFile. If you forget the chain, non-browser clients fail with "unable to get local issuer certificate" — see also the certificate chain explained.

SSLProtocol: turn everything legacy off

SSLProtocol -all +TLSv1.2 +TLSv1.3 explicitly disables everything and adds only the two modern versions. This is more robust than listing the legacy ones as -SSLv3 -TLSv1, because new insecure protocols are not allowed by default.

Ciphers and OCSP stapling

Keep SSLCipherSuite short and restricted to AEAD ciphers with ECDHE (forward secrecy). For TLS 1.3 the ciphers are fixed and not controlled by this directive. SSLUseStapling must sit in the global configuration, not inside the VirtualHost, and requires a stapling cache. Read more about cipher suites and OCSP stapling.

Test and graceful reload

# Validate the configuration
sudo apachectl configtest

# Graceful reload — in-flight requests finish first
sudo apachectl graceful

# Confirm what is served
openssl s_client -connect example.com:443 -servername example.com

More on swapping the certificate without dropping connections in certificate rotation without downtime, and on keeping it renewed automatically in the ACME pillar.

How CertControl verifies your Apache endpoints

Apache configurations often drown in old, copied directives — and a forgotten graceful means the old certificate is still served. CertControl scans the endpoint from the outside and confirms that the chain is complete, that only modern protocols are offered, and that the certificate is not about to expire — independent of what the configuration file says.

Frequently asked questions

Should intermediates go in SSLCertificateFile or SSLCertificateChainFile?

From httpd 2.4.8 you can put the whole chain in SSLCertificateFile (use fullchain.pem). On older versions you supply intermediates separately in SSLCertificateChainFile.

What does SSLProtocol -all +TLSv1.2 +TLSv1.3 mean?

It turns off all protocols and then adds only TLS 1.2 and 1.3. This is the safest form, because it does not inadvertently allow legacy or future insecure protocols.

Where is OCSP stapling configured in Apache?

SSLUseStapling and SSLStaplingCache belong in the global server configuration, not inside the individual VirtualHost. The cache is shared across hosts.

What is the difference between apachectl graceful and restart?

graceful lets each child process finish its current request before being reloaded with the new configuration — no connections are dropped. A restart interrupts everything immediately.

Should I set SSLHonorCipherOrder?

With TLS 1.2 it can make sense to let the server decide the order via SSLHonorCipherOrder on. For TLS 1.3 it has no effect, as cipher selection is handled differently.