Files
meezi/scripts/backup/RESTORE.md
T
soroush.asadi 32a7cf5b25
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 30s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 1m48s
ops: nightly DB backup + self-hosted uptime monitoring
Backup (production data-loss protection — was none):
- meezi-backup sidecar in docker-compose.yml runs pg_dump nightly at 02:00
  Tehran, gzip, 14-day rotation, atomic .partial→final, into ./backups
  (persists across deploys; rsync off-box per RESTORE.md).
- Wired into the deploy job (up -d --no-deps backup); takes one dump on boot.
- scripts/backup/pg-backup-loop.sh + RESTORE.md (restore + off-box guidance).

Monitoring:
- docker-compose.monitoring.yml: Uptime Kuma stack (own volume), stood up
  once, independent of app deploys.
- Caddyfile status.{$DOMAIN} route; docs/monitoring.md lists the exact
  monitors (incl. /q guest-menu 200 check) + TLS-expiry alerts (catches the
  ~90-day cert breakage early) + alert-channel setup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:45:07 +03:30

1.9 KiB

Meezi database backup & restore

How backups work

The meezi-backup container (in docker-compose.yml) runs a nightly pg_dump of the whole meezi database at 02:00 Asia/Tehran, gzips it, and keeps the last 14 days in the host ./backups directory (override with BACKUP_DIR). Filenames: meezi_YYYYMMDD_HHMMSS.sql.gz. One backup is also taken immediately when the container first starts.

Check it's running / list backups:

docker logs meezi-backup --tail 20
ls -lh ./backups

⚠️ Copy backups OFF the server

The bind-mounted ./backups survives a container/volume wipe, but not a disk failure. Add an off-box copy (run from the host via cron), e.g.:

# rsync to another host nightly at 03:00
0 3 * * * rsync -az --delete /path/to/meezi/backups/ user@backup-host:/srv/meezi-backups/

or rclone copy ./backups remote:meezi-backups to object storage.

Restore

  1. Pick a dump:
    ls -lh ./backups          # choose e.g. meezi_20260615_020000.sql.gz
    
  2. (Recommended) stop the API so nothing writes mid-restore:
    docker stop meezi-api
    
  3. Restore into the running Postgres container:
    gunzip -c ./backups/meezi_20260615_020000.sql.gz \
      | docker exec -i meezi-db psql -U meezi -d meezi
    
    For a clean restore into an empty DB, drop & recreate first:
    docker exec -i meezi-db psql -U meezi -d postgres -c "DROP DATABASE meezi;"
    docker exec -i meezi-db psql -U meezi -d postgres -c "CREATE DATABASE meezi OWNER meezi;"
    gunzip -c ./backups/<dump>.sql.gz | docker exec -i meezi-db psql -U meezi -d meezi
    
  4. Start the API again (it runs EF migrations on boot, which is a no-op if the dump is current):
    docker start meezi-api
    

Manual one-off backup

docker exec meezi-db pg_dump -U meezi --no-owner --no-privileges meezi \
  | gzip -9 > ./backups/meezi_manual_$(date +%Y%m%d_%H%M%S).sql.gz