Add daily encrypted borgmatic backup service

- /docker/backup: borgmatic container (daily 03:00 Berlin via BACKUP_CRON)
- Backs up /docker (ro) to local encrypted repo /var/backups/borg (repokey-blake2)
- Postgres prod+dev captured via pg_dumpall; live PG data/logs/build artifacts excluded
- Retention: keep_daily 7, keep_weekly 4, keep_monthly 6; runs prune/compact/create/check
- Secrets in backup/.env (gitignored, chmod 600)
This commit is contained in:
2026-05-31 22:29:46 +02:00
parent 02b4fe1fc0
commit e7a7cafa89
5 changed files with 163 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# Never commit secrets.
.env
+74
View File
@@ -0,0 +1,74 @@
# borgmatic configuration for linumiq.net — local encrypted daily backup (v1).
# borgmatic 2.x flat schema. Secrets are interpolated from the container
# environment (see ../.env): POSTGRES_PASSWORD_PROD, POSTGRES_PASSWORD_DEV,
# BORG_PASSPHRASE.
# ---------------------------------------------------------------------------
# What to back up (files)
# ---------------------------------------------------------------------------
source_directories:
- /docker
# Repository (bind-mounted from host /var/backups/borg).
repositories:
- path: /repository
label: linumiq-local
# Encryption passphrase (repokey-blake2). Set in ../.env, kept offsite too.
encryption_passphrase: ${BORG_PASSPHRASE}
# ---------------------------------------------------------------------------
# Exclusions: raw live PG data (captured via logical dumps below), transient
# logs, regenerable build artifacts, and remediation snapshots.
# ---------------------------------------------------------------------------
exclude_patterns:
- /docker/supabase/volumes/db/data
- /docker/dev/supabase/volumes/db/data
- /docker/supabase/volumes/logs
- /docker/dev/supabase/volumes/logs
- /docker/caddy/config/caddy/autosave.json
- sh:/docker/**/.remediation-backup
- sh:/docker/**/node_modules
- sh:/docker/**/.next
exclude_caches: true
exclude_if_present:
- .nobackup
# Keep the archive listing manageable.
one_file_system: false
# ---------------------------------------------------------------------------
# Postgres logical dumps (streamed into the archive, not written to disk).
# name "all" => pg_dumpall (roles + all databases + extensions).
# ---------------------------------------------------------------------------
postgresql_databases:
- name: all
hostname: supabase-db
port: 5432
username: postgres
password: ${POSTGRES_PASSWORD_PROD}
- name: all
hostname: supabase-dev-db
port: 5432
username: postgres
password: ${POSTGRES_PASSWORD_DEV}
# ---------------------------------------------------------------------------
# Retention
# ---------------------------------------------------------------------------
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
# Tag archives so prune groups them correctly.
archive_name_format: "linumiq-{now:%Y-%m-%dT%H:%M:%S}"
match_archives: "sh:linumiq-*"
# ---------------------------------------------------------------------------
# Consistency checks (run as part of the default daily action set).
# ---------------------------------------------------------------------------
checks:
- name: repository
- name: archives
# Surface command output/errors in logs.
+40
View File
@@ -0,0 +1,40 @@
name: backup
services:
borgmatic:
image: ghcr.io/borgmatic-collective/borgmatic:latest
container_name: borgmatic
hostname: linumiq-borgmatic
restart: unless-stopped
security_opt:
- no-new-privileges:true
environment:
TZ: Europe/Berlin
# Daily backup at 03:00 server-local time. The image writes this to
# /etc/crontabs/root and runs: borgmatic --stats -v 0
BACKUP_CRON: "0 3 * * *"
env_file:
- ./.env
volumes:
# Backup source (read-only — borgmatic never writes to /docker).
- /docker:/docker:ro
# Local borg repository (host-side, same disk; remote planned later).
- /var/backups/borg:/repository
# borgmatic configuration.
- ./borgmatic.d:/etc/borgmatic.d:ro
# Persist borg cache + security dir across container recreation so borg
# does not re-scan the whole repo or warn about an "unknown" repository.
- borg_cache:/root/.cache/borg
- borg_security:/root/.config/borg
networks:
# Reach the prod + dev Postgres containers (supabase-db / supabase-dev-db)
# by container name for the pg_dumpall hook.
- supabase_default
- supabase-dev_default
volumes:
borg_cache:
borg_security:
networks:
supabase_default:
external: true
supabase-dev_default:
external: true