#!/bin/sh # Back up the app's data under /data (the budget JSON files, imported PDFs/CSVs, # and uploaded images). This app stores everything as plain JSON files — there # is no SQLite database. # # Always writes a timestamped tar.gz to the local NAS path (/backups, mounted # from the host). ALSO pushes to Backblaze B2 — but only when a real bucket and # credentials are configured, so it's harmless before B2 is set up. # # rclone's B2 remote ("b2:") is configured from the RCLONE_CONFIG_B2_* env vars. # Runs once; the container loops it on BACKUP_INTERVAL. set -eu STAMP=$(date +%Y%m%d-%H%M%S) KEEP_DAYS="${BACKUP_KEEP_DAYS:-30}" LOCAL_DIR="/backups" echo "[backup ${STAMP}] starting" # 1. Local timestamped snapshot of everything under /data --------------------- mkdir -p "${LOCAL_DIR}" ARCHIVE="${LOCAL_DIR}/moon-data-${STAMP}.tar.gz" tar -czf "${ARCHIVE}" -C /data . echo "[backup ${STAMP}] local snapshot: ${ARCHIVE} ($(du -h "${ARCHIVE}" | cut -f1))" # prune old local snapshots find "${LOCAL_DIR}" -name 'moon-data-*.tar.gz' -type f -mtime +"${KEEP_DAYS}" -delete 2>/dev/null || true # 2. Optional Backblaze B2 push (only when a real bucket + key are set) -------- if [ -n "${B2_BUCKET:-}" ] && [ "${B2_BUCKET#__}" = "${B2_BUCKET}" ] \ && [ -n "${RCLONE_CONFIG_B2_ACCOUNT:-}" ] && [ "${RCLONE_CONFIG_B2_ACCOUNT#__}" = "${RCLONE_CONFIG_B2_ACCOUNT}" ]; then DEST="b2:${B2_BUCKET}/moon-household-budget" if rclone copyto "${ARCHIVE}" "${DEST}/snapshots/moon-data-${STAMP}.tar.gz" 2>/tmp/rclone.err; then rclone sync /data "${DEST}/current" 2>>/tmp/rclone.err || true rclone delete --min-age "${KEEP_DAYS}d" "${DEST}/snapshots" 2>/dev/null || true echo "[backup ${STAMP}] pushed to B2 (${B2_BUCKET})" else echo "[backup ${STAMP}] B2 push FAILED: $(head -1 /tmp/rclone.err 2>/dev/null)" fi else echo "[backup ${STAMP}] B2 not configured — local snapshot only" fi echo "[backup ${STAMP}] done"