Backup and restore
A backup is the only way back after a disk failure, a bad update or a compromised server. It is also a copy of your CA keys, so it needs care in both directions: it must exist, and it must not lie next to the secrets that open it.
- When to use this
- What is in a backup
- 1. The daily timer
- 2. A backup by hand, and its check
- 3. Copy it offsite
- 4. Restore drill on a spare host
- Check it worked
- When it fails
- What to store apart
- Next steps
When to use this
- Right after the installation, to confirm that the daily backup works.
- Before an update or any larger change.
- Once now, and again after every major upgrade, to rehearse a restore on a spare machine. A backup you never restored is a hope.
What is in a backup
myownpki backup DIR copies every database as one consistent copy while the server runs and writes a
manifest.json with a SHA-256 per file, the migration versions, the head of every audit chain and the
checkpoint key fingerprint.
| In the backup | Not in the backup |
|---|---|
system.db (users, sessions, the key ring), the instance and tenant audit logs, pki.db (CAs, certificates, encrypted keys) |
config.yaml. Copy /etc/myownpki/config.yaml yourself. |
auth.key, only if it lives in the data directory |
auth.key if auth.key_file points elsewhere. Back it up separately, or every user needs user reset-2fa after a restore. |
| The passphrase and the recovery key, on purpose |
The CA and certificate keys in the backup are encrypted with the root key. The backup alone cannot sign. The backup plus the passphrase or the recovery key can. That is why the three belong in three different places (see the last section).
1. The daily timer
install.sh installs and enables myownpki-backup.timer (unless you passed --no-backup-timer).
Once a day, at a random time in the first hour after midnight, it runs myownpki backup scheduled:
- a backup into
/var/backups/myownpki/<UTC time>, for example20261025T003512Z; - every restore check on it;
- only if the check passed, prune: the newest 14 scheduled backups stay, older ones go.
Prune never touches the backup that install.sh makes before an update (<time>-v<old version>), a
timer backup that failed its check (<time>-unverified), a directory that is not a complete backup,
or anything else you put there. See the table in
operations guide §6.1.
systemctl list-timers myownpki-backup.timer
journalctl -u myownpki-backup.service -o cat
runuser -u myownpki -- /usr/local/bin/myownpki backup prune /var/backups/myownpki --keep 14 --dry-run
Another number: install.sh --backup-keep 30. The dashboard warns when the newest timer backup is
older than 48 hours or when an -unverified directory exists.
2. A backup by hand, and its check
runuser -u myownpki -- /usr/local/bin/myownpki backup /var/backups/myownpki/before-change --config /etc/myownpki/config.yaml
DIR must not exist; a backup never overwrites anything. The command prints the audit heads, the
checkpoint key and whether auth.key is included. In a container:
docker compose run --rm -v "$PWD/backup:/backup" myownpki backup /backup/before-change
Check a backup without touching anything. The timer’s own check does not pin the checkpoint key, so do
this yourself with the fingerprint you wrote down at init:
runuser -u myownpki -- /usr/local/bin/myownpki backup verify /var/backups/myownpki/before-change --checkpoint-key <fingerprint>
3. Copy it offsite
/var/backups/myownpki is on the same disk as the data directory, so it does not survive that disk.
Copy it to another machine with whatever you already use. As an example with rsync, run by root
because the directory is mode 0700:
sudo rsync -a /var/backups/myownpki/ backup-host.homelab.lan:/srv/backups/myownpki/
Without --delete, rsync keeps on the target what the timer has pruned here, so prune there on your
own schedule. Keep the passphrase and the recovery key away from that machine.
4. Restore drill on a spare host
Use a machine that is not your production network if you can. A restored server that is unsealed does what the original does: it signs CRLs and runs monitoring and scans.
- Install the same release on the spare host, but do not run
init.install.shwrites a configuration and creates an empty data directory (Installation). Put your savedconfig.yamlin place if you need the same settings. -
Copy one backup directory to the spare host, for example into
/srv/restore-test/, and give it to the service user (the service user cannot read/root):chown -R myownpki:myownpki /srv/restore-test -
Check it, with the fingerprint from
init:runuser -u myownpki -- /usr/local/bin/myownpki backup verify /srv/restore-test/20261025T003512Z --checkpoint-key <fingerprint> -
Restore. The data directory must be empty or missing, and the server stopped. All checks run first (hashes, database integrity, audit chains and heads, the certificate name index) and nothing is written if one fails. Run it as root:
restorebuilds a work copy next to the data directory (/var/lib), where the service user cannot write. Then give the restored files to the service user:/usr/local/bin/myownpki restore /srv/restore-test/20261025T003512Z --config /etc/myownpki/config.yaml --checkpoint-key <fingerprint>chown -R myownpki:myownpki /var/lib/myownpki -
Start the server:
systemctl start myownpki - Sign in, then unseal with the passphrase that was valid when the backup was taken. If you changed
the passphrase since, the old one opens this backup. If you do not know it, set a new one with the
recovery key (
myownpki passphrase reset) and unseal with that. The UI andserve --unsealtake only a passphrase, never the recovery key itself. -
Check the result:
runuser -u myownpki -- /usr/local/bin/myownpki ca list --config /etc/myownpki/config.yamlrunuser -u myownpki -- /usr/local/bin/myownpki audit verify --config /etc/myownpki/config.yaml --checkpoint-key <fingerprint> - Write down how long it took and what was missing. Then stop the service and clear the spare host.
Check it worked
backup verifyends with “The backup passed every check of a restore.”restoreends with “Restored into … Start the server and unseal it …”.- After the unseal,
ca listshows your authorities andaudit verifyprintsOK. - Certificates issued after the backup are not in it. Their serial numbers are still in the certificates themselves.
When it fails
… is not empty – restore only into an empty data directory: stop the server and move the old data directory away first.- A check fails: nothing was restored. Try an older backup; the journal of the timer names the problem.
- The unseal is refused: you are using the wrong passphrase for this backup. Try the old one, or run
myownpki passphrase resetwith the recovery key and unseal with the new passphrase (operations guide §7). - Everyone is asked for a new second factor:
auth.keywas not in the backup. Put the old file where the configuration names it, or runuser reset-2fafor each user (operations guide §8). - More: Troubleshooting and Upgrade.
What to store apart
| Item | Where | Why |
|---|---|---|
| Unseal passphrase | A password manager. Not on the server, not in a script. | Opens the CA keys. Keep the old one with old backups. |
| Recovery key | On paper, in a safe. Not in the password manager, not on the backup disk. | The second way in. |
| Backups | Another machine or disk | They are the keys, encrypted. |
| Checkpoint key fingerprint | Written down | Needed for backup verify and restore. |
config.yaml, and auth.key if outside the data directory |
With your configuration backup | Not part of the backup. |
Check once a year that you can unseal and that the paper is readable.
Next steps
- Practice the failure cases: When things go wrong.
- Read about the audit log that every backup and restore writes to: The audit log.
- Put the habit in a calendar: Best practices.