Skip to content

Backups & Restore

Regular database backups are essential for any production deployment. Drizzle migrations are forward-only — there is no automatic rollback. Backups are your safety net.

Terminal window
docker compose -f compose.prod.yaml exec db \
pg_dump -U ${POSTGRES_USER:-archvault} ${POSTGRES_DB:-archvault} \
> backup-$(date +%Y%m%d-%H%M%S).sql
Terminal window
docker compose -f compose.prod.yaml exec -T db \
psql -U ${POSTGRES_USER:-archvault} ${POSTGRES_DB:-archvault} \
< backup-20260317-143000.sql

PostgreSQL supports two backup formats. Choose based on your needs:

Human-readable SQL dump. Easy to inspect and edit.

Terminal window
# Backup
pg_dump -U archvault archvault > backup.sql
# Restore
psql -U archvault archvault < backup.sql

Pros: readable, portable, easy to grep/edit Cons: larger file size, slower restore on large databases

Set up a cron job for daily backups with 7-day retention:

  1. Create a backup script:

    backup-archvault.sh
    #!/bin/sh
    set -e
    BACKUP_DIR="/opt/archvault/backups"
    COMPOSE_FILE="/opt/archvault/compose.prod.yaml"
    RETENTION_DAYS=7
    mkdir -p "$BACKUP_DIR"
    # Create backup
    docker compose -f "$COMPOSE_FILE" exec -T db \
    pg_dump -U archvault -Fc archvault \
    > "$BACKUP_DIR/archvault-$(date +%Y%m%d-%H%M%S).dump"
    # Remove backups older than retention period
    find "$BACKUP_DIR" -name "archvault-*.dump" -mtime +$RETENTION_DAYS -delete
    echo "Backup complete. $(ls -1 "$BACKUP_DIR"/archvault-*.dump | wc -l) backups retained."
  2. Make it executable:

    Terminal window
    chmod +x backup-archvault.sh
  3. Add a cron job (daily at 3 AM):

    Terminal window
    crontab -e
    0 3 * * * /opt/archvault/backup-archvault.sh >> /var/log/archvault-backup.log 2>&1

An untested backup is not a backup. Periodically verify by restoring to a throwaway container:

Terminal window
# Start a temporary PostgreSQL container
docker run --rm -d \
--name archvault-backup-test \
-e POSTGRES_USER=archvault \
-e POSTGRES_PASSWORD=testpass \
-e POSTGRES_DB=archvault \
postgres:18-alpine
# Wait for it to be ready
sleep 3
# Restore the backup
docker exec -i archvault-backup-test \
pg_restore -U archvault -d archvault --clean --if-exists \
< /opt/archvault/backups/archvault-20260317-030000.dump
# Verify table count
docker exec archvault-backup-test \
psql -U archvault -d archvault -c "\dt" | tail -3
# Clean up
docker stop archvault-backup-test

For disaster recovery, copy backups to cloud storage:

Terminal window
# AWS S3
aws s3 cp backup.dump s3://my-bucket/archvault/backup-$(date +%Y%m%d).dump
# Google Cloud Storage
gsutil cp backup.dump gs://my-bucket/archvault/backup-$(date +%Y%m%d).dump
# Backblaze B2
b2 upload-file my-bucket backup.dump archvault/backup-$(date +%Y%m%d).dump

Add the upload command to the end of your automated backup script for hands-off offsite copies.