feat(ops): nightly DB backups with rotation (#26)
CI / backend (push) Successful in 1m0s
CI / frontend (push) Successful in 14s
CI / format (push) Successful in 52s
CI / db-tests (push) Successful in 1m10s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 13s
CI / format (pull_request) Successful in 50s
CI / db-tests (pull_request) Successful in 51s
Deploy Staging / deploy (push) Successful in 17s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 55s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 56s
CI / backend (push) Successful in 1m0s
CI / frontend (push) Successful in 14s
CI / format (push) Successful in 52s
CI / db-tests (push) Successful in 1m10s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 13s
CI / format (pull_request) Successful in 50s
CI / db-tests (pull_request) Successful in 51s
Deploy Staging / deploy (push) Successful in 17s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 55s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 56s
This commit was merged in pull request #26.
This commit is contained in:
@@ -15,3 +15,6 @@ FRONTEND_ORIGIN=http://localhost:8081
|
|||||||
# Set DEV_MODE=true and MAX_MESSAGES=1000 to test against a large mailbox.
|
# Set DEV_MODE=true and MAX_MESSAGES=1000 to test against a large mailbox.
|
||||||
DEV_MODE=false
|
DEV_MODE=false
|
||||||
MAX_MESSAGES=0
|
MAX_MESSAGES=0
|
||||||
|
|
||||||
|
# Nightly DB backup rotation (days of dumps to keep in ./backups)
|
||||||
|
BACKUP_KEEP_DAYS=7
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ frontend/.vite/
|
|||||||
appsettings.*.local.json
|
appsettings.*.local.json
|
||||||
secrets.json
|
secrets.json
|
||||||
|
|
||||||
|
## DB backups (never commit dumps)
|
||||||
|
backups/
|
||||||
|
|
||||||
## Logs
|
## Logs
|
||||||
logs/
|
logs/
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
+3
-1
@@ -29,7 +29,9 @@ reverse proxy.
|
|||||||
mitigate (a third party reading the DB files) reduces to "someone with access to your
|
mitigate (a third party reading the DB files) reduces to "someone with access to your
|
||||||
machine" — mitigate it at the layer that actually works:
|
machine" — mitigate it at the layer that actually works:
|
||||||
- **Use full-disk or volume encryption** on the host (BitLocker/LUKS) — strongly recommended.
|
- **Use full-disk or volume encryption** on the host (BitLocker/LUKS) — strongly recommended.
|
||||||
- **Encrypt backups** of the `pgdata` volume the same way.
|
- **Encrypt backups**: nightly `pg_dump` rotation runs via the compose `backup` service
|
||||||
|
into `./backups/` (git-ignored) — keep that directory on an encrypted disk and copy it
|
||||||
|
off-machine. Restore: `docker compose exec -T postgres psql -U inboxintel -d inboxintel < backups/<file>.sql`.
|
||||||
- Before any **multi-user** deployment, revisit per the multi-provider security design
|
- Before any **multi-user** deployment, revisit per the multi-provider security design
|
||||||
(host admins must not be able to read members' mail — plaintext bodies break that promise).
|
(host admins must not be able to read members' mail — plaintext bodies break that promise).
|
||||||
2. **DB connection is not TLS** — Postgres is only reachable on the compose-internal network /
|
2. **DB connection is not TLS** — Postgres is only reachable on the compose-internal network /
|
||||||
|
|||||||
@@ -22,6 +22,37 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|
||||||
|
# Nightly logical backups (RECOMMENDATIONS #3 — previously there were NONE). Dumps
|
||||||
|
# rotate after BACKUP_KEEP_DAYS. The ./backups host directory should live on an
|
||||||
|
# encrypted disk and be included in your off-machine backup regime (see SECURITY.md).
|
||||||
|
# Restore: docker compose exec -T postgres psql -U inboxintel -d inboxintel < backups/<file>.sql
|
||||||
|
backup:
|
||||||
|
image: pgvector/pgvector:pg16
|
||||||
|
entrypoint: /bin/sh
|
||||||
|
command:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
while true; do
|
||||||
|
ts=$$(date -u +%Y%m%d-%H%M%S)
|
||||||
|
if pg_dump -h postgres -U inboxintel -d inboxintel > /backups/inboxintel-$$ts.sql.tmp; then
|
||||||
|
mv /backups/inboxintel-$$ts.sql.tmp /backups/inboxintel-$$ts.sql
|
||||||
|
echo "backup OK: inboxintel-$$ts.sql"
|
||||||
|
else
|
||||||
|
rm -f /backups/inboxintel-$$ts.sql.tmp
|
||||||
|
echo "backup FAILED at $$ts" >&2
|
||||||
|
fi
|
||||||
|
find /backups -name 'inboxintel-*.sql' -mtime +$${BACKUP_KEEP_DAYS:-7} -delete
|
||||||
|
sleep 86400
|
||||||
|
done
|
||||||
|
environment:
|
||||||
|
PGPASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in deploy/.env}
|
||||||
|
BACKUP_KEEP_DAYS: ${BACKUP_KEEP_DAYS:-7}
|
||||||
|
volumes:
|
||||||
|
- ./backups:/backups
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
api:
|
api:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
Reference in New Issue
Block a user