Aller au contenu

Backups

Overview

Backups run daily at 02:00 via cron and use a three-tier retention strategy.

/opt/docker/backups/
├── scripts/backup.sh     Cron script (source of truth: aether repo)
├── daily/                Rotated after 7 days
├── weekly/               Rotated after 28 days (copied on Sundays)
└── archive/              Kept indefinitely (RPPS snapshots)

What Gets Backed Up

Data Format Tier Retention
aletheia_prod database .dump (pg_dump custom) daily + weekly 7d / 28d
aletheia_staging database .dump (pg_dump custom) daily + weekly 7d / 28d
umami database .dump (pg_dump custom) daily + weekly 7d / 28d
Prod media files .tar.gz (excludes annuaire/) daily 7d
Staging media files .tar.gz (excludes annuaire/) daily 7d
RPPS snapshots .tar.gz per dated folder archive Indefinite
Encrypted secrets .enc files in git Git repo Permanent

What is NOT backed up

  • Dev environment database and media (recreatable from staging)
  • Redis data (ephemeral cache + Celery broker — rebuilds on restart)
  • Loki logs (7-day retention, ephemeral by design)
  • Docker images (pulled from registries)

How It Works

Schedule, retention, and scope

Cron schedule:

0 2 * * * /opt/docker/backups/scripts/backup.sh >> /var/log/backups.log 2>&1

Retention: daily = 7 days, weekly = 28 days, archive = indefinite

Databases backed up:

  • aletheia_prod
  • aletheia_staging
  • umami

Verify the cron is installed:

crontab -l | grep backup

Backup flow

  1. Database dumpspg_dump -Fc (custom format, compressed) for each database listed above
  2. Media archivestar czf of prod and staging media, excluding RPPS annuaire/ folders
  3. RPPS archive — each new dated snapshot in media/{env}/annuaire/YYYY-MM-DD/ gets compressed into archive/rpps_{env}_{date}.tar.gz (only once, skips if archive already exists)
  4. Weekly copy — on Sundays, the day's backups are copied to weekly/
  5. Cleanup — files older than retention period are deleted. Archive is never cleaned.

File naming

daily/aletheia_prod_20260419_020001.dump
daily/media_aletheia_prod_20260419_020001.tar.gz
weekly/aletheia_prod_20260419_020001.dump
archive/rpps_prod_2026-04-15.tar.gz

Manual Operations

Trigger a backup manually

/opt/docker/backups/scripts/backup.sh

Output goes to stdout. The cron job appends to /var/log/backups.log.

Check backup integrity

# List recent backups with sizes
ls -lh /opt/docker/backups/daily/

# Verify a dump file is valid (lists TOC without restoring)
docker exec -i shared_postgres pg_restore -l < /opt/docker/backups/daily/aletheia_prod_YYYYMMDD_HHMMSS.dump

Restore a database from backup

# 1. Copy the dump into the container
docker cp /opt/docker/backups/daily/aletheia_prod_YYYYMMDD_HHMMSS.dump shared_postgres:/tmp/restore.dump

# 2. Drop and recreate the database (CAUTION: destroys current data)
docker exec shared_postgres psql -U admin -c \
  "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='aletheia_prod' AND pid <> pg_backend_pid();"
docker exec shared_postgres dropdb -U admin aletheia_prod
docker exec shared_postgres createdb -U admin -O aletheia_prod aletheia_prod

# 3. Restore
docker exec shared_postgres pg_restore -U aletheia_prod -d aletheia_prod \
  -Fc --no-owner /tmp/restore.dump

# 4. Restart the app to reconnect
cd /opt/docker/aletheia/repo && make restart ENV=prod

Restore media files

tar xzf /opt/docker/backups/daily/media_aletheia_prod_YYYYMMDD_HHMMSS.tar.gz \
  -C /opt/docker/aletheia/media/prod/

Restore an RPPS snapshot

# List available snapshots
ls /opt/docker/backups/archive/rpps_prod_*.tar.gz

# Extract a specific snapshot
mkdir -p /tmp/rpps_restore
tar xzf /opt/docker/backups/archive/rpps_prod_2026-04-15.tar.gz -C /tmp/rpps_restore/

Monitoring

  • Weekly check: verify a recent backup exists and has a reasonable size (see recurring tasks)
  • Disk space: backup storage grows over time — monitor with du -sh /opt/docker/backups/
  • Cron failures: check /var/log/backups.log for errors

Gap: Off-site backups

All backups currently stay on the same server. If the server is lost, backups are lost too. Until off-site backups are implemented, periodically copy /opt/docker/backups/daily/ to external storage.