Skip to content

$ cat ./posts/security/tls-certificate-rotation-without-downtime.sh

-rw-r--r-- 1.6K #security #tls

TLS certificate rotation without downtime

by chris · 2 min read · /security


Certificate renewal is automated almost everywhere now. Certificate deployment often is not, which is why expiry incidents still happen with a valid certificate sitting on disk.

1. Reload rather than restart

sudo nginx -t && sudo systemctl reload nginx

A reload re-reads the configuration and the certificate files while existing connections finish. A restart drops them. Test the configuration first — reload on a broken config leaves the old workers running and the error only in the log.

2. Hook the renewal, do not schedule it separately

# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/sh
set -eu
systemctl reload nginx
systemctl reload postfix

A deploy hook runs only when a certificate actually changed. A cron job that reloads nightly whether or not anything moved is noise that hides the one night it mattered.

3. Verify from outside

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null 
  | openssl x509 -noout -dates -subject

Read the dates from the socket, not from the file. The two disagree exactly when something is wrong, which is the only time you are looking.

4. Alert on the served certificate

Monitor days-to-expiry against what the endpoint presents, per hostname, including the ones behind a load balancer that terminates separately. Alert at fourteen days so there is a working week to fix it, and page at three. An alert that fires on the morning of expiry is a notification, not a warning.

← cd .. fris@linux:~/blog$ man security