Backups
A backup counts only once it has been verified. A copy leaves the server encrypted. Rotating the key never strands the backups the old key wrote.
Local backups
klyrn backup create example.com
klyrn backup list example.com
klyrn backup schedule example.com daily --keep 7
klyrn backup schedule example.com none
klyrn backup delete 42
A backup contains the site's files, its databases, its cron entries, its mail and its DNS
records, with a manifest.json carrying a SHA-256 for every file. Caches, logs, the temp
directory and node_modules are excluded. They are rebuildable, and they
are most of the size.
A backup is marked verified only after the archive is listed back and every checksum in the manifest matches.
Retention keeps the last 7 by default, or whatever --keep says, between 1 and
60. The scheduled pass runs a site at most once every 23 hours. Archives live under
/var/lib/klyrn/backups/, readable by root only.
Restoring
klyrn backup restore 42
klyrn backup restore 42 --yes # skip the confirmation prompt
A restore verifies every checksum first, unpacks into a staging directory, and only then swaps into place. It can recreate a site that was deleted. That includes its database and its user, with a fresh password written into the site's configuration.
In the panel it is a six-step wizard ending in type-to-confirm, because a restore overwrites a working site as readily as a broken one. A restore is also checked against the account's disk limit, using the backup's own size.
Mail and downloads
Mail can be restored one mailbox at a time. A restore adds what is missing and never overwrites newer mail.
A backup can be downloaded from the panel through a single-use link.
Off-site copies
klyrn backup remote # destination and its state
klyrn backup remote list example.com # what is in the bucket
klyrn backup remote fetch klyrn/example.com/20260906-090000
klyrn backup remote delete klyrn/example.com/20260906-090000
The destination is any S3-compatible bucket you control. Copies are encrypted on the server with XChaCha20-Poly1305 before they leave it, so the bucket operator never holds plaintext. Uploads above 1 GB are multipart.
One object in the destination is not encrypted: a small keyinfo.json
holding a key fingerprint and a couple of counts, never a key. With it, a rebuilt
server can say "import key 3f1a9c04b7d25e88" where it would otherwise say only
"wrong key".
Keys and rotation
klyrn backup key list # version, fingerprint, created, which one writes
klyrn backup key export # the current key, in full
klyrn backup key export <fingerprint>
klyrn backup key rotate --note "annual rotation"
klyrn backup key import klyrn-bk1-… --make-current
Rotating adds a key. It never removes one. A backup that could be restored yesterday can still be restored today.
A fingerprint is the first eight bytes of SHA-256 of the key, hex encoded. It identifies a key and cannot be used as one. A restore picks the key by the fingerprint the backup recorded. For backups written before fingerprints existed it tries each key in turn, newest first. The archive format authenticates its first chunk, so a wrong key is rejected immediately.
Importing a key to read another server's backups does not change what new
backups are encrypted with. The imported key goes second from the end unless you pass
--make-current. Importing a key this server already holds is refused by
fingerprint.
What a backup is not
- Backups are per site. For the whole server, see the recovery manifest.
- You cannot back up only the files or only the database. A backup is the whole site.
- One S3-compatible destination at a time. Verified against MinIO.
- Nothing is deleted from the bucket when a local backup is pruned. Removing a remote copy is an explicit command.