Step 8
Backups
A simple, repeatable backup routine for the central DB, every tenant DB, and file storage.
What to back up
- PostgreSQL - central DB + one DB per tenant.
- MinIO / S3 bucket - all uploaded files.
- .env - secrets. Store separately and encrypted.
Quick backup (one command)
bash
# Dump every DB (central + tenants) into one file docker compose exec -T postgres \ pg_dumpall -U "$(grep ^DB_USERNAME .env | cut -d= -f2)" \ | gzip > "fchat-pg-$(date +%F).sql.gz" # Snapshot the MinIO bucket docker run --rm \ -v fchat_minio-data:/data \ -v "$(pwd)":/backup \ alpine tar czf "/backup/fchat-minio-$(date +%F).tgz" -C /data .
Restore
bash
# Restore Postgres (will OVERWRITE existing data) gunzip -c fchat-pg-2026-05-21.sql.gz \ | docker compose exec -T postgres psql -U "$DB_USERNAME" # Restore MinIO docker run --rm \ -v fchat_minio-data:/data \ -v "$(pwd)":/backup \ alpine sh -c 'cd /data && tar xzf /backup/fchat-minio-2026-05-21.tgz'
Automate with cron
On the host, add to root's crontab:
cron
# Daily 03:00 - keep last 14 days 0 3 * * * cd /opt/fchat && ./backup.sh && find ./backups -mtime +14 -delete
!
Off-site is non-negotiable
Backups on the same server protect against application bugs, not disasters. Push them to S3, Backblaze B2, or an off-site box via rclone / restic / rsync.
Encrypted off-site (recommended)
Install rclone on the host, configure a remote, and push your dumps:
bash
rclone copy ./backups remote:fchat-backups --crypt-remote=secret
Test your restores
A backup you have never restored is not a backup. Once a month, spin up a fresh server, restore the dump, and confirm the platform loads.