# 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: ```bash 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.: ```bash # 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: ```bash ls -lh ./backups # choose e.g. meezi_20260615_020000.sql.gz ``` 2. (Recommended) stop the API so nothing writes mid-restore: ```bash docker stop meezi-api ``` 3. Restore into the running Postgres container: ```bash 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: ```bash 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/.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): ```bash docker start meezi-api ``` ## Manual one-off backup ```bash 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 ```