Back up and restore
Pack a Docker Compose deployment’s data into an archive on a schedule, so you can bring it back on another host or after losing data. The commands are in the compose runbook, “Backup & restore”.
How it works
Section titled “How it works”| What you do | What happens |
|---|---|
Run backup.sh from cron |
All of DATA_DIR becomes a timestamped tar.gz, and old generations are pruned |
Keep AF_MASTER_KEY in a vault separate from the data |
Someone who steals only the archive cannot read members’ credentials |
To restore, put the same key back, then run restore.sh |
The Control Plane comes up, and each workspace returns when a member presses Start |
What the archive holds
Section titled “What the archive holds”| Included | Not included |
|---|---|
control-plane.db (tenants, members, ports, tokens) |
shared/jvm (a large JDK that can be fetched again) |
Each member’s home (working trees, dotfiles, the encrypted secrets.enc) |
AF_MASTER_KEY (it lives in .env and is left out on purpose) |
Each member’s claude-config (Claude login state, in plaintext) |
|
| Caddy’s certificates (so a restore does not run into Let’s Encrypt’s rate limits) |
That is everything needed to restore on another host.
Take a backup
Section titled “Take a backup”Run deploy/compose/backup.sh. In production, run it from cron.
| Setting | Meaning |
|---|---|
OUT_DIR |
Where archives go. Point it at another volume or remote storage. The default is deploy/compose/backups/ |
KEEP |
How many generations to keep. The default is 7; 0 keeps them all |
--no-stop |
Takes the snapshot without stopping the Control Plane. Use it only when the caller guarantees nothing is writing |
The runbook has an example cron entry. After each run, generations beyond KEEP are deleted automatically.
Effect on members
Section titled “Effect on members”- By default
backup.shstops the Control Plane and Caddy for a few seconds to take a consistent SQLite snapshot, then starts them again - Members’ workspaces (
af-ws-*) keep running. They are not compose services. Sessions stay connected and work carries on - For those few seconds, Console sign-in and API relaying do not answer; that is all
Restore
Section titled “Restore”Do this on a clean host, or on a host that lost its data.
- Prepare
.envand put back the sameAF_MASTER_KEYas the source, from your vault - Run
deploy/compose/restore.sh <archive> - Bring up the Control Plane and Caddy with
docker compose up -d - Members (or an administrator) press Start on each workspace in the Console
Three things to watch:
| Watch | Why |
|---|---|
AF_MASTER_KEY must be the same value |
With a different key, or none, members’ credentials cannot be decrypted. Check the vault restore first |
Keep the last directory name of DATA_DIR the same |
The parent path may differ (/srv → /mnt, say); the Control Plane re-roots it at start. The last name must match the archive’s top-level directory, or restore.sh refuses |
| Right after a restore there are no workspace containers | They are not compose services, so the archive does not hold them. Start has the Control Plane recreate them with the restored database’s ports and tokens, and the home’s secrets.enc and claude-config bring back connections and the Claude login |
Other deployment types
Section titled “Other deployment types”| Type | Backup and restore |
|---|---|
ECS (ecs / ecs-ec2) |
The ECS runbook, “EFS backup and restore” |
| Kubernetes | The Kubernetes runbook, “Backups, point-in-time recovery and the restore rehearsal” |
Related
Section titled “Related”- Upgrade: always take a backup before an upgrade
- Handle the deployment keys: what losing
AF_MASTER_KEYmeans
For agents
Send this prompt to your agent to read this page.
Read https://agent-fleet.org/docs/operate/run/backup-restore/index.md