Adds a server-wide backup capability beyond the existing ops_dashboard pg_dump flow: - Daily systemd timer (03:30) runs pg_dumpall + Forgejo dump, then restic to a local NAS repo and an offsite Backblaze B2 repo with Object Lock. Phase-based script with single-instance flock, structured statusfile, systemd hardening, and live-datadir excludes (Postgres / Forgejo) so the dumps stay authoritative. - Ops-agent gets nine new read-only/trigger commands (snapshots, stats, status, logs, plus two triggers) backed by sudoers-whitelisted wrapper scripts that source /etc/restic-backup.env so the agent never sees the restic password or B2 keys. - Two new flows (server_backup_full, server_backup_restore_test) drive the dashboard's "Backup now" and "Restore test" buttons. - /settings/backups gains a Server backup section with overall + per-phase status, NAS / B2 snapshot tables, restore-size / raw-data / dedup-ratio stats, and the last restore-test result. The existing pg_dump section is preserved unchanged. - Runbook docs/runbooks/server-backup.md follows the tailscale-setup pattern (plan + addendum) and covers B2 Object Lock + scoped keys, Forgejo subplan with isolated restore-test stack, the off-server maintenance flow for B2 prune, and the integrity-check schedule. Code-only change — installation on scrum4me-srv follows the runbook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
44 lines
2.3 KiB
Text
44 lines
2.3 KiB
Text
# Copy to /etc/restic-backup.env on the host. Permissions: 0600 root:root.
|
|
# RESTIC_PASSWORD lives in /etc/restic-backup.password (mode 0400 root:root)
|
|
# — the backup script sets RESTIC_PASSWORD_FILE from there, so the password
|
|
# never appears in the process listing or this env file.
|
|
|
|
# ── Restic repositories ────────────────────────────────────────────────────
|
|
# Local NAS path (must be mounted before the timer fires; see runbook).
|
|
RESTIC_REPO_NAS=/mnt/backup-server/restic/scrum4me-srv
|
|
|
|
# Backblaze B2 repo, format: b2:<bucket-name>:<prefix>
|
|
# Bucket must have Object Lock (Governance) with default retention >= 30 days.
|
|
RESTIC_REPO_B2=b2:scrum4me-srv-backup:scrum4me-srv
|
|
|
|
# ── Backblaze B2 server key ────────────────────────────────────────────────
|
|
# Capabilities REQUIRED: listBuckets, listFiles, readFiles, writeFiles
|
|
# Capabilities FORBIDDEN: deleteFiles, deleteKeys, bypassGovernance
|
|
# Create with:
|
|
# b2 application-key create \
|
|
# --bucket scrum4me-srv-backup \
|
|
# --name-prefix scrum4me-srv \
|
|
# server-backup-key \
|
|
# listBuckets,listFiles,readFiles,writeFiles
|
|
B2_ACCOUNT_ID=REPLACE_WITH_B2_KEY_ID
|
|
B2_ACCOUNT_KEY=REPLACE_WITH_B2_APPLICATION_KEY
|
|
|
|
# ── Forgejo backup target (optional — set to skip if Forgejo not deployed) ─
|
|
# Container name as it appears in `docker ps`. Set to "" or comment out to
|
|
# skip the Forgejo phases entirely.
|
|
FORGEJO_CONTAINER=forgejo
|
|
# Path to app.ini INSIDE the Forgejo container (used by `forgejo dump -c`).
|
|
FORGEJO_CONFIG=/data/gitea/conf/app.ini
|
|
# Postgres database name for Forgejo (empty = use SQLite, skip forgejo_db_dump).
|
|
FORGEJO_DB_NAME=forgejo
|
|
# Postgres container + role for Forgejo's DB (defaults match scrum4me stack).
|
|
FORGEJO_DB_CONTAINER=scrum4me-postgres
|
|
FORGEJO_DB_USER=scrum4me
|
|
|
|
# ── Scrum4Me Postgres (required for postgres_dump phase) ───────────────────
|
|
PG_CONTAINER=scrum4me-postgres
|
|
PG_DUMPALL_USER=scrum4me
|
|
|
|
# ── Optional bandwidth limit for restic B2 upload (KiB/s; 0 = unlimited) ──
|
|
# Translated by the script into `restic --limit-upload "$BACKUP_LIMIT_UPLOAD_KIB"`.
|
|
# BACKUP_LIMIT_UPLOAD_KIB=5000
|