I lost access to a private key once. Not because someone stole it — I upgraded a server, thought I’d moved everything, and realized a week later that the key for one of the domains was gone. The certificate was still valid, the site was working with the cached config, but when it came time to renew, there was nothing to renew with. I had to reissue the certificate from scratch.
After that, I got serious about certificate backups.
What You Actually Need to Back Up
Not everything in your SSL/TLS setup needs to be backed up with the same urgency:
Private keys — the most critical. If you lose the private key, you cannot use the certificate. Period. You’ll need to generate a new key, create a new CSR, and get the certificate reissued.
Certificates — important to back up for historical records and quick recovery, but they’re less critical than keys because you can re-download them from your CA (most CAs let you do this).
Certificate chains — same as above. Often downloadable from the CA.
CA bundles — less urgent, but good practice to keep a copy.
Configuration — not the certificates themselves, but the configuration that references them (Nginx/Apache vhosts, etc.). If you have to rebuild a server, having the config saved separately is very helpful.
So in terms of priority: keys > certificates > configuration > chains.
Where Keys and Certificates Live
On a typical Linux server:
- Let’s Encrypt:
/etc/letsencrypt/live/<domain>/and/etc/letsencrypt/archive/<domain>/ - Manual installations: often in
/etc/ssl/,/etc/nginx/ssl/, or wherever you copied them - Apache: sometimes in
/etc/apache2/ssl/
For Let’s Encrypt specifically, I back up the entire /etc/letsencrypt/ directory. This includes the account keys, certificates, private keys, and renewal configurations. If I need to migrate to a new server, I can restore this directory and renewals will continue working.
A Simple Backup Script
Here’s the script I’ve used for years as a starting point:
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/var/backups/ssl"
DATE=$(date +%Y%m%d)
BACKUP_FILE="${BACKUP_DIR}/ssl_backup_${DATE}.tar.gz.enc"
PASSPHRASE_FILE="/root/.ssl_backup_passphrase"
# Create backup dir if it doesn't exist
mkdir -p "$BACKUP_DIR"
# Create encrypted backup of Let's Encrypt directory
tar czf - /etc/letsencrypt/ /etc/nginx/ssl/ 2>/dev/null | \
openssl enc -aes-256-cbc -pbkdf2 -pass file:"$PASSPHRASE_FILE" \
-out "$BACKUP_FILE"
echo "Backup created: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))"
# Remove backups older than 90 days
find "$BACKUP_DIR" -name "ssl_backup_*.tar.gz.enc" -mtime +90 -delete
echo "Done."
The passphrase is stored in /root/.ssl_backup_passphrase. That file should be readable only by root (chmod 400). The backup itself is AES-256-CBC encrypted — so even if the backup file is somehow accessed, the private keys inside are protected.
To restore:
openssl enc -d -aes-256-cbc -pbkdf2 -pass file:/root/.ssl_backup_passphrase \
-in /var/backups/ssl/ssl_backup_20240115.tar.gz.enc | \
tar xzf - -C /
This restores to the original paths.
Automating with Cron
Add to root’s crontab (sudo crontab -e):
# Daily SSL certificate backup at 2 AM
0 2 * * * /usr/local/bin/ssl_backup.sh >> /var/log/ssl_backup.log 2>&1
I also add a weekly check that emails me if any certificate in the backup is expiring soon, but that’s more of a monitoring concern than a backup concern.
Offsite Backups
A local backup is better than nothing, but if the server is lost entirely, the local backup goes with it. I copy the encrypted backup to a remote location:
rsync to another server:
rsync -avz /var/backups/ssl/ backupuser@backup-server:/backups/ssl/
AWS S3:
aws s3 cp "$BACKUP_FILE" s3://my-backup-bucket/ssl/
Rclone (works with many providers):
rclone copy /var/backups/ssl/ remote:ssl-backups/
Because the files are already encrypted before uploading, you don’t need to worry about the storage provider seeing your private keys.
Let’s Encrypt Renewal Configs
One thing people miss: backing up the renewal configuration in /etc/letsencrypt/renewal/ is important. This is where certbot stores how each certificate should be renewed — which domains, which authenticator plugin (http-01, dns-01), which hooks to run.
Without this, you can restore the certificate files but certbot won’t know how to renew them automatically. It’ll just see expired certs and no renewal config.
The entire /etc/letsencrypt/ directory structure looks like:
/etc/letsencrypt/
├── accounts/ # ACME account keys
├── archive/ # All historical cert files
├── live/ # Symlinks to current certs
├── renewal/ # Renewal configuration per domain
└── renewal-hooks/ # Pre/post renewal scripts
Back up all of it.
Testing Your Backups
I restore from backup once a year on a test server. It sounds like overkill but I’ve caught issues this way — a script that was writing corrupted archives, a passphrase file that had a typo, a permission issue on the restored key file.
A minimal test:
# Check the backup file is valid and readable
openssl enc -d -aes-256-cbc -pbkdf2 -pass file:/root/.ssl_backup_passphrase \
-in /var/backups/ssl/ssl_backup_latest.tar.gz.enc | \
tar tzf - | head -20
This decrypts and lists the contents without actually extracting anything. If it completes without error, the archive is intact and the passphrase is correct.
Key Storage Beyond Backups
Some keys are important enough that backup alone isn’t sufficient. For wildcard certificates or certs used across many services, I keep a copy in:
- A password manager’s secure notes (for really small deployments)
- HashiCorp Vault’s KV secrets engine
- AWS Secrets Manager or Parameter Store (encrypted)
The advantage of a secrets manager over a backup archive is that you can retrieve individual secrets without having to restore an entire backup. It also gives you access control and audit logging.
Certificate Inventory
Related to backups but slightly different: maintaining an inventory of what certificates you have, where they’re installed, and when they expire. Without this, you might back up certificates but not know which ones are critical.
I maintain a simple spreadsheet with: domain, CA, expiry date, server(s) where installed, backup location, renewal method. For more structure, tools like crtmgr.com handle this tracking automatically and can alert you before certificates expire — which is the thing that matters most operationally.
Windows Considerations
On Windows Server, certificates are stored in the Windows Certificate Store (certmgr.msc). Backing them up is different:
- Export via certmgr.msc: right-click certificate → All Tasks → Export → choose “Yes, export the private key” → PKCS#12 format
- PowerShell:
Export-PfxCertificate -Cert cert:\LocalMachine\My\<thumbprint> -FilePath C:\backups\cert.pfx****** -String "password" -Force -AsPlainText)
Store the PFX file in a secure location. The PFX includes both the certificate and private key, protected by a password.
Certificate backups aren’t glamorous, but they’re one of those things you’re very glad you did when something goes wrong. The basic setup — an encrypted local backup and an offsite copy — takes an afternoon to implement and then runs automatically forever. Worth the investment.