# Backup and Restore (V6.0 Phase 4) This guide defines operational backup/restore for clean-slate recovery of the Docker runtime and Synology replication. ## 1. Backup artifacts (clean-slate recovery set) - Primary local backup location: `./data/backups` - Local files created per run: - `postgres-YYYYMMDD-HHMMSS.dump` (PostgreSQL custom dump via `pg_dump -Fc`) - `backup-YYYYMMDD-HHMMSS.manifest` (artifact index) - Synology files created per run (when `SYNOLOGY_BACKUP_DIR` is set): - `postgres-YYYYMMDD-HHMMSS.dump` (copied from local) - `config-YYYYMMDD-HHMMSS.tar.gz` (deployment config snapshot: `.env.production`, `docker-compose.production.yml`, `deploy/cloudflared/config.yml` when present) - `logs-YYYYMMDD-HHMMSS.tar.gz` (snapshot of `/app/data/logs`) - `backup-YYYYMMDD-HHMMSS.manifest` - Synology incremental media mirror (copied only if missing): - `uploads/homepage.md` - `uploads/documents/**` - `uploads/photos/**` ## 2. Creating backups Use the scripted command from the repository root: ```bash sh deploy/backup/create_postgres_backup.sh ``` Environment overrides: - `BACKUP_DIR` (default `./data/backups`) - `BACKUP_RETENTION_DAYS` (default `14`) - `SYNOLOGY_BACKUP_DIR` (if set, dump/config/log/manifest are copied to this mounted path and media is synced incrementally) - `ENV_FILE` (default `.env.production`) - `COMPOSE_FILE` (default `docker-compose.production.yml`) Example with Synology mount: ```bash SYNOLOGY_BACKUP_DIR=/mnt/synology-backups sh deploy/backup/create_postgres_backup.sh ``` ## 2.1 Persisting Synology mount (LXC) The backup copy step depends on a mounted NAS path. Manual `mount` commands are lost after reboot unless persisted. Use the template (copy, edit placeholders, then run): ```bash cp deploy/backup/mount_synology_cifs.example.sh /root/mount_synology_cifs.sh nano /root/mount_synology_cifs.sh sh /root/mount_synology_cifs.sh ``` Then add the printed `/etc/fstab` line (with your real values) so the mount survives reboot. Recommended pattern: - Keep NAS credentials in a local file like `/etc/samba/credentials/transcription-synology` with `chmod 600`. - Keep `SYNOLOGY_BACKUP_DIR` in `.env.production` aligned to that mount point (for example `/mnt/synology-backups`). - The script will also read `SYNOLOGY_BACKUP_DIR` from `ENV_FILE` when not exported in the shell. ## 3. Restoring from backup Restore requires downtime for app + worker writes. 1. Stop app and worker: - `docker compose --env-file .env.production -f docker-compose.production.yml stop app worker` 2. Restore: - `sh deploy/backup/restore_postgres_backup.sh ./data/backups/postgres-YYYYMMDD-HHMMSS.dump` - if `SYNOLOGY_BACKUP_DIR/uploads` exists, media is restored from the Synology mirror. - if `SYNOLOGY_BACKUP_DIR/config-YYYYMMDD-HHMMSS.tar.gz` exists, config is restored from that archive. 3. Start app and worker: - `docker compose --env-file .env.production -f docker-compose.production.yml start app worker` 4. Validate `/healthz` and run one smoke workflow. Notes: - Config restore extracts the archived files back into the current repository path. - Legacy full-archive restores (`uploads-*.tar.gz`, `config-*.tar.gz` beside the dump) are still supported for older backups. ## 4. Retention and recovery targets - Retention baseline: keep at least 14 days of backups locally. - Synology copy: replicate each backup artifact set to DS420j mounted path. - Periodic restore drill: run at least once per release cycle to verify recovery.