Backup and Restore¶
Self-hosted deployments are responsible for their own backups — there is no
managed backup service in the Docker Compose path. This page covers the two
supported approaches: logical dumps (pg_dump/psql, recommended) and
volume-level snapshots (faster for large databases, less portable).
Logical backup (recommended)¶
Dump¶
docker compose exec -T postgres pg_dump -U rai -d rai --format=custom \
> raise-backup-$(date +%Y%m%d-%H%M%S).dump
--format=custom produces a compressed, pg_restore-compatible file — the
recommended format for anything beyond trivial data volumes. For a
human-readable plain-SQL dump instead (e.g. to diff schema changes):
docker compose exec -T postgres pg_dump -U rai -d rai --format=plain \
> raise-backup-$(date +%Y%m%d-%H%M%S).sql
Restore¶
Custom format, into a fresh database (drop and recreate first if
restoring over an existing one — pg_restore does not overwrite by
default):
docker compose exec -T postgres dropdb -U rai rai
docker compose exec -T postgres createdb -U rai rai
docker compose exec -T postgres pg_restore -U rai -d rai --no-owner \
< raise-backup-20260827-120000.dump
Plain-SQL format:
After restoring, restart the server so any in-process caches (e.g. connection pool state) pick up a clean slate:
Verify a restore¶
curl http://localhost:8080/health # expect "database": "connected"
docker compose exec postgres psql -U rai -d rai -c \
"SELECT count(*) FROM organizations;"
Volume-level backup (alternative)¶
The compose file's data volume is named raise-commons-dev-pgdata
(see docker-compose.md). For a full binary snapshot instead of a logical
dump — faster for very large databases, but only restorable to a
compatible PostgreSQL major version:
# Stop postgres first — a live volume copy while writes are in-flight is not
# a consistent snapshot.
docker compose stop postgres
docker run --rm \
-v raise-commons-dev-pgdata:/volume \
-v "$(pwd)":/backup \
alpine tar czf /backup/pgdata-$(date +%Y%m%d-%H%M%S).tar.gz -C /volume .
docker compose start postgres
Restore by extracting the tarball back into a fresh volume before starting
postgres:
docker compose stop postgres
docker volume rm raise-commons-dev-pgdata # destructive — confirm first
docker volume create raise-commons-dev-pgdata
docker run --rm \
-v raise-commons-dev-pgdata:/volume \
-v "$(pwd)":/backup \
alpine tar xzf /backup/pgdata-20260827-120000.tar.gz -C /volume
docker compose start postgres
Recommended schedule¶
There is no built-in scheduler in this Compose stack. Wire the logical dump command into your own cron / systemd timer / CI job, e.g.:
# /etc/cron.d/raise-backup — daily at 02:00
0 2 * * * root cd /path/to/raise-commons && docker compose exec -T postgres pg_dump -U rai -d rai --format=custom > /var/backups/raise/raise-$(date +\%Y\%m\%d).dump 2>> /var/log/raise-backup.log
Retain backups off-host (object storage, another server) — a backup that lives on the same disk as the database it protects does not protect against disk failure.