Skip to content

Backup and Restore

Doug edited this page Jun 24, 2026 · 2 revisions

Backup & Restore

Everything that matters lives in one PostgreSQL database (gdx), so a backup is a pg_dump of it. Uploaded files live in the gdx_uploads volume — back that up too if you store attachments.

Golden rule: take a backup before any risky change (upgrade, migration, bulk edit), and test a restore periodically — an untested backup is a guess.

Manual backup

From the repo root (portable across setups — targets the db compose service):

docker compose -f gdx_dispatch/docker/docker-compose.yml exec -T db \
  pg_dump -U gdx gdx | gzip > "gdx_$(date +%Y%m%d_%H%M%S).sql.gz"

Uploaded files:

docker run --rm -v gdx_uploads:/data -v "$PWD":/out alpine \
  tar czf /out/gdx_uploads_$(date +%Y%m%d).tar.gz -C /data .

Automated daily backup

The repo ships scripts/backup-db.sh — a cron-friendly dump-to-/var/backups/gdx with a 30-day prune and an inventory log:

0 2 * * * /opt/gdx_dispatch/scripts/backup-db.sh >> /var/log/gdx-backup.log 2>&1

Adapt the container name inside the script to your deployment (it targets a specific postgres container name, not the compose service). For most installs the portable docker compose ... exec db pg_dump form above is simpler.

Pre-update snapshots

docker/update.sh automatically snapshots the database to backups/ before pulling a new image. Keep those — they're your rollback if an update goes wrong. See Updating.

Restore

Restoring replaces data — only do it deliberately. Cleanest is to restore into a freshly recreated database so old rows can't collide:

COMPOSE="docker compose -f gdx_dispatch/docker/docker-compose.yml"

# 1. stop the app/workers so nothing writes mid-restore (leave db running)
$COMPOSE stop app celery-high celery-low celery-beat

# 2. drop & recreate the database
$COMPOSE exec -T db psql -U gdx -d postgres -c "DROP DATABASE IF EXISTS gdx;"
$COMPOSE exec -T db psql -U gdx -d postgres -c "CREATE DATABASE gdx OWNER gdx;"

# 3. load the dump
gunzip -c gdx_20260624_020000.sql.gz | $COMPOSE exec -T db psql -U gdx gdx

# 4. bring the stack back (entrypoint re-runs migrations idempotently)
$COMPOSE up -d

To restore in place instead (e.g. the update.sh rollback path), pipe the gunzip'd dump straight into psql -U gdx gdx without dropping — fine when the schema matches.

Restore drill (do this before you need it)

  1. Take a backup.
  2. Restore it into a throwaway database (CREATE DATABASE gdx_drill; → load → spot-check a few tables).
  3. Confirm row counts look right. Drop the drill DB.

See also

  • Updating — upgrades take a pre-update snapshot for you.
  • Architecture — what's in the database.

Clone this wiki locally