Replace the SSL Certificate on Apache HTTP Server
Swap the SSL certificate on Apache 2.4 (Debian/Ubuntu and RHEL): find the vhost files, build the chain, check the key, apachectl configtest, graceful reload and verification.
Apache HTTP Server 2.4 reads the certificate and key from SSLCertificateFile and
SSLCertificateKeyFile in each TLS virtual host. Since Apache 2.4.8, the certificate
file can contain the intermediate certificates after the server certificate, so
SSLCertificateChainFile is no longer needed.
| Debian / Ubuntu | RHEL / Rocky / Alma | |
|---|---|---|
| Configuration | /etc/apache2/ | /etc/httpd/ (TLS: conf.d/ssl.conf) |
| Typical certificate paths | /etc/ssl/certs/, /etc/ssl/private/ | /etc/pki/tls/certs/, /etc/pki/tls/private/ |
| Service | apache2 | httpd |
Before you begin
-
Find which virtual host uses which files.
apachectl -Slists the virtual hosts and their configuration files;grepshows the certificate lines:sudo apachectl -S sudo grep -Rn 'SSLCertificate' /etc/apache2 /etc/httpd 2>/dev/null -
Prepare the server certificate (
leaf.pem), the intermediate(s) (intermediates.pem) and the private key (private.key), all PEM. Do not include the root CA. -
Back up the current files with their permissions:
sudo cp -a /etc/pki/tls/certs/www.crt /etc/pki/tls/certs/www.crt.bak sudo cp -a /etc/pki/tls/private/www.key /etc/pki/tls/private/www.key.bak
Step-by-step certificate replacement
-
Build the chain - server certificate first - and check that the key belongs to it:
cat leaf.pem intermediates.pem > fullchain.pem openssl verify -untrusted intermediates.pem leaf.pem openssl pkey -in private.key -pubout | sha256sum openssl x509 -in leaf.pem -noout -pubkey | sha256sumopenssl verifymust printOK, and the two hashes must be identical. -
Install the files at the paths the virtual host uses. The key can be readable by root only: Apache's parent process runs as root and reads it, also on a graceful reload, before handing work to the child processes.
sudo install -m 0644 fullchain.pem /etc/pki/tls/certs/www.crt sudo install -m 0600 private.key /etc/pki/tls/private/www.key sudo restorecon -v /etc/pki/tls/certs/www.crt /etc/pki/tls/private/www.key # SELinux systemsSSLEngine on SSLCertificateFile "/etc/pki/tls/certs/www.crt" SSLCertificateKeyFile "/etc/pki/tls/private/www.key" -
Test the configuration, then reload gracefully:
sudo apachectl configtest sudo systemctl reload httpd # RHEL # sudo systemctl reload apache2 # Debian/Ubuntuconfigtestchecks the syntax, not whether key and certificate match - that is why step 1 checks it. On both distributions,systemctl reloadperforms a graceful restart: running requests finish, new connections get the new certificate, nobody is disconnected.
Encrypted private keys
A key with a passphrase makes Apache ask for it on every start and reload - a service
started by systemd cannot answer, and the start fails. Either use an unencrypted key
protected by file permissions (remove the passphrase with
openssl pkey -in encrypted.key -out private.key), or configure SSLPassPhraseDialog
with a program that supplies the passphrase, as your key-management policy requires.
Verify the new certificate
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null
sudo journalctl -u httpd --since "10 minutes ago" # or -u apache2Check subject and SAN, issuer, expiry date and that the intermediate is sent - for every
name-based virtual host, with its own name as -servername.
Rollback
Copy the .bak files back, run apachectl configtest, and reload. Keep the backup
until the new certificate is verified.
Common problems
- The change was made in the wrong configuration tree (
apache2vshttpd) or for the wrong virtual host. - The chain is incomplete, or the key does not match.
- An encrypted key blocks the start or reload.
- SELinux denies access to files without the right label (
restorecon). - A different SNI virtual host was tested.
Automating certificate replacement with aethercert
The aethercert Apache preset writes the configured certificate/chain and private-key
files and runs the configured reload command. The default is systemctl reload apache2;
on RHEL-based systems set it to systemctl reload httpd.
See Deploy targets for the fields this preset takes, what it needs on the host, and how far it has been verified.