Restoring a Postgres Backup
Restore a Kopia snapshot produced by the backups compose profile (or a
pre-deploy safety snapshot) into a running HoloMUSH instance.
Find the snapshot
Section titled “Find the snapshot”Snapshots are identified by Kopia snapshot IDs, not filesystem paths. List the 10 most recent snapshots:
ssh holomush@game.holomush.dev \ 'docker compose -f /opt/holomush/compose.yaml --profile tunnel --profile backups \ exec -T backup kopia snapshot list --all --max-results=10'List only the pinned pre-deploy snapshots (one per release):
ssh holomush@game.holomush.dev \ 'docker compose -f /opt/holomush/compose.yaml --profile tunnel --profile backups \ exec -T backup kopia snapshot list --all --tags=pre-deploy:'Grab the snapshot ID from the leftmost column (e.g. kabc123...).
Restore path A: into a throwaway Postgres (verification)
Section titled “Restore path A: into a throwaway Postgres (verification)”Use this path to verify a snapshot without touching the running sandbox.
Requires the kopia binary and the repository password on your machine.
# On your local machinemkdir /tmp/restore-test && cd /tmp/restore-test
# One-time: connect your local kopia to the repoexport KOPIA_PASSWORD="<your-KOPIA_SANDBOX_PASSWORD>"export AWS_ACCESS_KEY_ID="<your-DO_SPACES_ACCESS_KEY>"export AWS_SECRET_ACCESS_KEY="<your-DO_SPACES_SECRET_KEY>"kopia repository connect s3 \ --bucket=holomush-sandbox-backups \ --endpoint=nyc3.digitaloceanspaces.com
# Pull the chosen snapshot contents to a filekopia snapshot restore <snapshot-id> ./backup.sql
# Spin up a throwaway Postgres and load the dumpdocker run --rm -d --name pg-restore-test \ -e POSTGRES_USER=holomush -e POSTGRES_PASSWORD=verify -e POSTGRES_DB=holomush \ -p 5433:5432 postgres:18-alpine
sleep 3PGPASSWORD=verify psql -h localhost -p 5433 -U holomush -d holomush < backup.sql
# Spot-check tablesPGPASSWORD=verify psql -h localhost -p 5433 -U holomush -d holomush \ -c "SELECT count(*) FROM events"
docker rm -f pg-restore-testRestore path B: into the live sandbox (destructive)
Section titled “Restore path B: into the live sandbox (destructive)”WARNING: This overwrites the running sandbox’s database. Take a pinned manual backup first.
ssh holomush@game.holomush.devcd /opt/holomush
# 1. Fresh pinned backup of current statedocker compose --profile tunnel --profile backups \ exec backup /usr/local/bin/backup.sh --tag=manual-pin:pre-restore
# 2. Stop services that write to the DBdocker compose stop core gateway
# 3. Restore the chosen snapshot contents to a file in the backup containerSNAPSHOT_ID=<id>docker compose --profile tunnel --profile backups \ exec -T backup kopia snapshot restore "${SNAPSHOT_ID}" /tmp/restore.sql
# 4. Drop and recreate the DBdocker compose exec -T postgres psql -U holomush -d postgres <<'SQL'DROP DATABASE holomush;CREATE DATABASE holomush OWNER holomush;SQL
# 5. Load the dump into the fresh DB (use the backup container's network# connection to postgres; it can psql because the image includes# postgresql-client)docker compose --profile tunnel --profile backups \ exec -T backup sh -c \ 'PGPASSWORD="${PGPASSWORD}" psql -h postgres -U holomush -d holomush < /tmp/restore.sql'
# 6. Restart servicesdocker compose --profile tunnel --profile backups up -d
# 7. Verifydocker compose exec -T gateway curl -sf http://localhost:8080/healthzRollback after a bad deploy
Section titled “Rollback after a bad deploy”If a release broke the sandbox, restore from the pinned pre-deploy snapshot taken at the start of the deploy workflow:
# Find the pre-deploy snapshot for the broken releasessh holomush@game.holomush.dev \ 'docker compose -f /opt/holomush/compose.yaml --profile tunnel --profile backups \ exec -T backup kopia snapshot list --tags=pre-deploy:v0.3.0'
# Follow Restore path B with the resulting snapshot ID, then redeploy the# previous good tag via the deploy-sandbox workflow workflow_dispatch.