Skip to content

Backups and recovery exports

baum uses two complementary forms of protection:

  • Backups contain the PostgreSQL database, object storage, local Git repositories, and non-secret configuration.
  • Recovery exports contain the installation configuration, credentials, and secrets that backups deliberately exclude. They are encrypted to an age recipient that you control.

You need both to recover from the loss of the appliance. Keep them off the baum server and in separate, access-controlled storage.

The appliance takes a backup daily and before an update. It keeps the seven most recent completed runs locally under /var/lib/baum/backups/ by default. Local backups do not protect you if the VM or its disk is lost, so configure an S3-compatible destination:

Terminal window
sudo baumctl backup destination set \
--endpoint s3.example.com \
--region eu-west-2 \
--bucket baum-backups \
--prefix production \
--access-key-id ACCESS_KEY_ID \
--retention 30

The command prompts for the secret access key without displaying it. The endpoint must be a host and optional port, without a URL path. TLS is enabled by default; use --secure=false only for a trusted endpoint that does not support TLS. The destination must not be the appliance’s primary object storage.

--retention controls the number of completed remote runs retained and defaults to 30. baum verifies the destination by writing, reading, and removing a probe before saving the configuration.

Check the saved destination, then take an initial backup:

Terminal window
sudo baumctl backup destination status
sudo baumctl backup
sudo baumctl doctor

A successful run prints its local directory. In remote storage, each run is stored below the configured prefix using a UTC timestamp. baum uploads backup.json last; its presence marks the remote run as complete.

Install age on a trusted operator workstation and generate an X25519 identity there, not on the baum server:

Terminal window
age-keygen -o baum-recovery-key.txt
age-keygen -y baum-recovery-key.txt

The second command prints the public recipient, which begins with age1. The identity file contains the private key. Store it in a password manager, secrets vault, or another protected recovery system, and make sure authorized operators can retrieve it if the usual administrator is unavailable. Never copy the private identity to the baum server merely to create an export.

Copy only the public age1... recipient to the appliance and run:

Terminal window
sudo baumctl recovery export \
--recipient age1EXAMPLE_REPLACE_WITH_YOUR_RECIPIENT \
--output /tmp/baum-recovery.age

Move the resulting encrypted bundle off the appliance, verify that the stored copy is readable, and remove the server-side copy. The bundle includes the installed release definition, baum configuration, GitHub App details, and appliance secrets. It does not include the database, objects, or Git repository data; those remain in the backups.

Create a new recovery export after changing baum secrets, configuration, GitHub App credentials, storage credentials, or the installed release. Retain at least the export that corresponds to the release used by your recoverable backups.

Restoring stops the application and replaces its database and stored data. For a local completed backup, run:

Terminal window
sudo baumctl restore \
/var/lib/baum/backups/20260812T120000Z \
--yes

To download a completed run from the configured destination and restore it, use its timestamp:

Terminal window
sudo baumctl restore --from-destination 20260812T120000Z --yes

The installed baum release must match the release recorded in the backup. If it does not, baumctl tells you which version to install or roll back to first. After the restore, run sudo baumctl status and sudo baumctl doctor.

On a replacement supported Ubuntu VM, install the server prerequisites as described in Self-host baum. Transfer the encrypted bundle and, only for the duration of recovery, the age identity to the replacement host. Import the installation state:

Terminal window
sudo baumctl recovery import \
--identity /path/to/baum-recovery-key.txt \
--input /path/to/baum-recovery.age

The import verifies the bundle, its checksums, and its signed release manifest before installing the recovered configuration and secrets. Then reconcile the appliance and restore the matching off-host backup:

Terminal window
sudo baumctl apply
sudo baumctl restore --from-destination 20260812T120000Z --yes
sudo baumctl doctor

Securely remove the copied private identity from the replacement host when recovery is complete. Practice this procedure periodically on an isolated host; an untested backup and an unavailable private key are not a recovery plan.