Dockerize: self-contained stack + B2 backup sidecar

This commit is contained in:
Bonna
2026-06-06 14:25:45 -05:00
parent fa3c030b36
commit 7f2057f139
9 changed files with 173 additions and 3 deletions

13
backup/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
# Tiny rclone + sqlite sidecar that backs up /data to Backblaze B2 on a loop.
FROM alpine:3.20
RUN apk add --no-cache rclone sqlite tzdata
COPY backup.sh /backup.sh
RUN chmod +x /backup.sh
ENV BACKUP_INTERVAL=86400
# Run once on boot, then every BACKUP_INTERVAL seconds. A failed run is logged
# but does not kill the loop.
CMD ["sh", "-c", "while true; do /backup.sh || echo '[backup] FAILED'; sleep \"${BACKUP_INTERVAL}\"; done"]

34
backup/backup.sh Normal file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
# Snapshot the app's data to Backblaze B2 via rclone.
# - SQLite DB: a consistent .backup snapshot (safe while the app is running)
# - uploads: mirrored to B2
# rclone's B2 remote ("b2:") is configured entirely from RCLONE_CONFIG_B2_*
# env vars (set in .env / compose). Runs once; the container loops it.
set -eu
STAMP=$(date +%Y%m%d-%H%M%S)
DEST="b2:${B2_BUCKET}/moon-household-budget"
KEEP_DAYS="${BACKUP_KEEP_DAYS:-30}"
echo "[backup ${STAMP}] starting"
# 1. SQLite snapshot (only if a db file is present)
if [ -f /data/app.db ]; then
sqlite3 /data/app.db ".backup '/tmp/app-${STAMP}.db'"
rclone copyto "/tmp/app-${STAMP}.db" "${DEST}/db/app-${STAMP}.db"
rm -f "/tmp/app-${STAMP}.db"
echo "[backup ${STAMP}] db snapshot uploaded"
else
echo "[backup ${STAMP}] no /data/app.db — skipping db snapshot"
fi
# 2. Uploaded images (and anything else under /data except the live db)
if [ -d /data/uploads ]; then
rclone sync /data/uploads "${DEST}/uploads"
echo "[backup ${STAMP}] uploads synced"
fi
# 3. Prune old db snapshots
rclone delete --min-age "${KEEP_DAYS}d" "${DEST}/db" 2>/dev/null || true
echo "[backup ${STAMP}] done"