1.9 KiB
1.9 KiB
| id | title | status | assignee | created_date | labels | dependencies | priority | ||
|---|---|---|---|---|---|---|---|---|---|
| task-013 | Automated database backups and offsite storage | Done | 2026-03-15 09:00 |
|
high |
Description
No critical database has automated backups. No data leaves this single server. A disk failure or compromise would lose all source code (Gitea), business data (ERPNext), photos (Immich), wiki/blog content (p2p-db), and email (Mailcow). This is the highest priority infrastructure gap.
Acceptance Criteria
- #1 Automated daily pg_dump for Gitea-DB (Postgres) — 3.1MB
- #2 Automated daily mysqldump for ERPNext MariaDB — 2.3MB
- #3 Automated daily mysqldump for p2p-db (MariaDB) — 707MB
- #4 Automated daily pg_dump for Immich Postgres — 620MB
- #5 Automated daily Mailcow backup (mariadb-dump) — 1.1MB
- #6 Off-server storage — rclone sync to Cloudflare R2 (plex-media/db-backups/)
- #7 Backup retention policy (7 days local, synced to R2)
- #8 Backup monitoring — Uptime Kuma push monitor (ID 199, 48h heartbeat interval)
Notes
Approach: Centralized backup container
Deploy an Alpine container with cron, database clients (pg_dump, mariadb-dump), and rclone. Runs scheduled dumps for all databases, compresses, and pushes to R2.
Template
rphotos backup script at /opt/apps/rphotos-online/backup-database.sh has a good pattern (pg_dumpall with 30-day retention).
Database credentials needed
- Gitea-DB: Postgres, accessible via
gitea-dbcontainer - ERPNext: MariaDB at
/opt/erpnext/(host-only) - p2p-db: MariaDB, root password in container env
- Immich: Postgres at
/opt/immich/postgres(host bind mount) - Mailcow: MySQL in
mailcowdockerized-mysql-mailcow-1
R2 storage
r2-mount container already has rclone configured for Cloudflare R2. Can reuse config for backup uploads.