linumiq_net-user e7a7cafa89 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)
2026-05-31 22:29:46 +02:00
2026-05-31 10:18:50 +02:00
2026-05-31 10:18:50 +02:00
2026-05-31 10:18:50 +02:00
2026-05-31 10:18:50 +02:00
2026-05-31 10:18:50 +02:00
2026-05-29 17:12:19 +02:00

/docker — linumiq.net remote access stack

Networks

Shared external docker network: edge (created with docker network create edge).

Shared env

/docker/.env — DOMAIN, LE_EMAIL.

Per-service secrets

/docker/<svc>/.env, all chmod 600, owned root:root. See /docker/SECRETS.md for the inventory.

Service inventory (Wave A + Wave B)

Service Compose dir Container name Listens Image
Supabase stack /docker/supabase supabase-* kong :8000, edge :9000 (internal) supabase/* (pinned per compose)
Caddy /docker/caddy caddy :80, :443 caddy:2.10.2-alpine
frps /docker/frps frps :7000 ctrl, :7080 vhost, :7500 dash snowdreamtech/frps:0.65.0
Redis /docker/redis redis :6379 (edge net only) redis:7.2-alpine
stripe-stub /docker/stripe-stub stripe-stub 127.0.0.1:4242 stripe-stub:1.0.0 (local build)
bandwidth-worker /docker/bandwidth-worker bandwidth-worker (no inbound) bandwidth-worker:1.0.0 (local build)

Start order

  1. cd /docker/redis && docker compose --env-file .env up -d
  2. cd /docker/supabase && docker compose up -d
  3. cd /docker/frps && docker compose up -d
  4. cd /docker/caddy && docker compose up -d
  5. cd /docker/stripe-stub && docker compose up -d
  6. cd /docker/bandwidth-worker && docker compose up -d
  7. (later) cd /docker/web && docker compose up -d

Stop order

Reverse of the above. docker compose down per directory.

Edge functions

Mounted from /docker/supabase/volumes/functions/. The main function is a router that reads the first URL path segment as the function name.

  • Via Kong: POST http://127.0.0.1:8000/functions/v1/<name>
  • Direct (intra-edge network, e.g. frps auth plugin): POST http://supabase-edge-functions:9000/<name>

After editing a function, cd /docker/supabase && docker compose restart functions (or up -d functions if env changed).

Wave B specifics

  • frps.toml enables [[httpPlugins]] name="auth" pointing at http://supabase-edge-functions:9000/auth-webhook.
  • supabase-edge-functions reads REDIS_URL from /docker/supabase/.env.
  • bandwidth-worker polls http://frps:7500/api/proxy/http every 60s; deltas go to public.usage_samples and public.tunnels.bytes_used via PostgREST.

Backups

Daily encrypted backups via borgmatic (/docker/backup).

Service Compose dir Container Schedule Image
borgmatic /docker/backup borgmatic daily 03:00 (Berlin) ghcr.io/borgmatic-collective/borgmatic:latest
  • Source: /docker (mounted read-only). Repository: /var/backups/borg (local host disk for v1; remote planned later). Encryption: repokey-blake2.
  • Databases: prod (supabase-db) + dev (supabase-dev-db) captured via pg_dumpall (roles + all DBs), streamed into the archive. The container is attached to supabase_default + supabase-dev_default to reach them.
  • Excluded: live PG data dirs (supabase/volumes/db/data), logs, caddy/.../autosave.json, .remediation-backup, node_modules, .next.
  • Retention: keep_daily 7, keep_weekly 4, keep_monthly 6.
  • Schedule: built-in cron via BACKUP_CRON env (0 3 * * *), running borgmatic --stats -v 0 (default action set: prune, compact, create, check).
  • Secrets: /docker/backup/.env (chmod 600, gitignored) holds POSTGRES_PASSWORD_PROD, POSTGRES_PASSWORD_DEV, BORG_PASSPHRASE. Store BORG_PASSPHRASE offsite — losing it makes the repo unrecoverable.

Operations

cd /docker/backup
docker compose up -d                                  # start the scheduler
docker compose run --rm --entrypoint borgmatic borgmatic list           # archives
docker compose run --rm --entrypoint borgmatic borgmatic create --stats # manual backup
docker compose run --rm --entrypoint borgmatic borgmatic check          # verify integrity

Restore a database dump:

cd /docker/backup
ARCH=$(docker compose run --rm --entrypoint borgmatic borgmatic list --json \
  | python3 -c "import sys,json;print(json.load(sys.stdin)[0][\"archives\"][-1][\"archive\"])")
docker compose run --rm -v /tmp/restore:/restore --workdir /restore \
  --entrypoint borgmatic borgmatic extract --archive "$ARCH" \
  --path "borgmatic/postgresql_databases/supabase-db:5432/all"
# then: psql -U postgres -f /tmp/restore/borgmatic/postgresql_databases/supabase-db:5432/all
S
Description
No description provided
Readme
135 KiB
Languages
Python 49.8%
PLpgSQL 45.5%
Shell 2.8%
Dockerfile 1.9%