Scheduled, encrypted, verified backups of the platform and of user data, to S3-compatible storage
and/or another server, with restore from the panel. Host: backups.<d>. Binary: backupsd. Stage 4.
The repository password is generated at setup and shown once with a printable recovery kit; it is also
sealed with the instance master key. Losing both means losing the backups, and the panel says so.
-
backupsd keeps destinations, plans and runs; xvii-node runs restic and pg_dump/pg_restore as root
over its socket (/backup/sources|init|run|snapshots|forget|check|files|dump|restore|drill).
-
Sources: /etc/xvii (path:etc), the release store (path:releases, so a new server needs nothing
else), every service database (db:xvii_<service>) and data folder (path:<service>). A plan with no
sources takes them all, including services installed later.
-
Destinations: S3-compatible (endpoint, bucket, prefix, keys), SFTP (an ed25519 key pair is made; its
public half goes to the server's authorized_keys), a local folder. Passwords and keys are sealed
with DATA_DIR/seal.key; the recovery kit (repository, password, keys) shows once at creation and
then only in a panel session, logged.
-
Verification: weekly restic check --read-data-subset 5% per destination, monthly drill per
database (restore into xvii_drill_*, count tables and rows, drop).
-
Restores: a database into a new name or in place (the service stops meanwhile), a folder into a new
folder or in place, one file as a download. xvii server restore HOST --kit FILE brings the whole
instance back on a fresh server: /etc/xvii, releases, databases, folders, then the services.
-
Superusers only; MCP tools backups_overview, backups_list_plans, backups_list_destinations,
backups_list_runs, backups_list_snapshots, backups_run_plan, backups_check_destination.
-
Telegram channel destination (for small instances, offsite for free): the node exports a source
as one stream (pg_dump custom format, or a folder's tar.gz), backupsd seals it with AES-256-GCM over
64 KiB chunks (key from the destination's password with scrypt; chunk i has nonce i, the last one a
flag) and sends it as documents of 303 chunks (19.9 MB, under the Bot API's 20 MB download limit),
then a manifest document listing the parts with their SHA-256 and the salt. No deduplication: every
snapshot is full. Retention deletes the messages; the weekly check downloads a random part and opens
it; drills and restores stream the parts back through the node (/backup/drillstream, /backup/import).
-
Apps' databases (stage 5): plans with all sources take every running database apps manages
(app:<id>, listed by GET apps/api/v1/databases). The node fetches the dump from apps
(/api/v1/apps/{id}/dump, backupsd's own token) into restic backup --stdin; a dump that fails midway
removes its snapshot. Restores are in place: restic dump streams back to apps' restore endpoint. A
Telegram destination takes the same stream through backupsd. Drills cover the platform's databases
only.
Next: drills of app databases in a scratch container, volumes of other apps.