Replace an SSL Certificate on HAProxy Without Downtime
Swap an HAProxy PEM bundle without downtime: build and check it, reload or hot-update it through the Runtime API, keep disk and memory in sync, verify SNI and roll back.
HAProxy usually loads one PEM file per certificate that contains the server certificate, the intermediate certificates and the private key. A replacement becomes active either with a reload or - without any reload - through the Runtime API.
Before you begin
- Find the certificate paths HAProxy uses: the
crtarguments of thebind ... ssllines inhaproxy.cfg. Acrtcan name a single file, a directory (every file in it is loaded) or a crt-list file (a list of certificate files with per-SNI options). - Back up the current file:
cp -p /etc/haproxy/certs/site.pem /root/site.pem.bak. - For the Runtime API route: the admin socket must be enabled with admin level in the
globalsection, for examplestats socket /run/haproxy/admin.sock mode 660 level admin, andsocatmust be installed.
Build and check the bundle
cat leaf.pem intermediates.pem private.key > site.pem
chmod 0600 site.pem
openssl x509 -in site.pem -noout -subject -enddate
openssl pkey -in private.key -pubout | sha256sum
openssl x509 -in leaf.pem -noout -pubkey | sha256sumThe order is server certificate, intermediates, private key. The two hashes must match.
Option 1: replace the file and reload
-
Install the new file next to the old one and move it into place (a rename on the same file system replaces it in one step):
install -m 0600 site.pem /etc/haproxy/certs/site.pem.new mv /etc/haproxy/certs/site.pem.new /etc/haproxy/certs/site.pem -
Check the configuration - this also loads and checks the new certificate - then reload:
haproxy -c -f /etc/haproxy/haproxy.cfg && systemctl reload haproxyWith the usual systemd setup (master-worker mode), a reload starts new workers with the new certificate while the old ones finish their existing connections.
For a certificate directory or crt-list, replace exactly the file of the certificate you are renewing and keep its file name, so the SNI selection and crt-list options stay the same.
Option 2: hot-update through the Runtime API
set ssl cert opens a transaction with the new content, commit ssl cert activates it,
abort ssl cert cancels it. The path must be the one HAProxy loaded the certificate
from:
printf 'set ssl cert /etc/haproxy/certs/site.pem <<\n%s\n\n' "$(cat site.pem)" | \
socat stdio /run/haproxy/admin.sock
echo "commit ssl cert /etc/haproxy/certs/site.pem" | socat stdio /run/haproxy/admin.sockRuntime API changes live only in memory. Also install the file on disk - step 1 of
option 1, without the reload - or the next restart brings the old certificate back.
A certificate file HAProxy has not loaded yet first needs a slot with new ssl cert
and must be referenced by a bind line or crt-list.
Verify the new certificate
echo "show ssl cert /etc/haproxy/certs/site.pem" | socat stdio /run/haproxy/admin.sock
openssl s_client -connect lb.example.com:443 -servername app.example.com -showcerts </dev/nullshow ssl cert prints the loaded certificate's subject, serial number and Not After
date - it must be the new one. Then check over the network, with each hostname as
-servername. With several HAProxy nodes, update and check each one.
Rollback
- After a reload: move
/root/site.pem.bakback into place,haproxy -c, reload. - After a Runtime API update: run the same
set/commitwith the backup file's content, and restore the file on disk too.
Common problems
- The bundle lacks the private key, or the parts are in the wrong order.
- The Runtime API was updated, but not the file on disk, so a restart brings back the old certificate.
- A different certificate is selected by SNI from a directory or crt-list.
- The admin socket is not enabled with
level admin.
Automating certificate replacement with aethercert
The aethercert HAProxy target builds the combined PEM bundle. It can use set ssl cert
and commit ssl cert through a Runtime API socket for a live update, or fall back to
the configured reload command.
See Deploy targets for the fields this preset takes, what it needs on the host, and how far it has been verified.