From 5b63a69a2c4675d7b56bbba48e3b8957a8195ca0 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Mon, 28 Sep 2026 14:24:57 +0700 Subject: [PATCH] chore(backup): support a second offsite repo (restic-2.env) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backup-relay.sh now pushes the archive to restic.env AND, if present, restic-2.env — so adding an R2/B2 bucket gives true 3-2-1 (local + CVM + object storage) instead of replacing one offsite with another. Each repo is sourced in its own subshell so RESTIC_* don't leak between them. Verified with a throwaway local second repo: both pushes ran, both snapshots exist. Also documents the umask trap (mode-600 cache dirs break restic). --- AGENTS.md | 10 ++++++++-- scripts/backup-relay.sh | 36 +++++++++++++++++++++++++----------- scripts/restic.env.example | 4 ++++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index db93ef9..924708d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -732,8 +732,14 @@ Rules: `~/.config/skatespots/cvm.env`) so no key/host lives in tracked files. `~/.config/skatespots/restic.env` (600, outside the repo) holds the repo URL + the generated `RESTIC_PASSWORD` — **that password is required to restore; keep a - copy in a password manager**. A second offsite (Cloudflare R2) can be added by - pointing the same file at an S3 repo. + copy in a password manager**. A second offsite is supported: put another repo + (e.g. Cloudflare R2 / Backblaze B2) in **`~/.config/skatespots/restic-2.env`** + and `backup-relay.sh` pushes to **both** — true 3-2-1 (local + CVM + object + storage). Verified 2026-09-28 with a throwaway second repo. + - ⚠️ **Don't run restic under a restrictive `umask`.** restic creates its cache + dirs from the umask, and a mode-600 dir has no execute bit → "permission + denied" on `~/.cache/restic//version`. If it happens: + `find ~/.cache/restic -type d ! -perm -u+x -exec chmod u+rwx {} +`. - **Restore drill (proven 2026-09-28):** `node scripts/drill-relay.mjs [port]` starts a throwaway in-memory NIP-01 relay (`ws`, no persistence); then `node scripts/restore-relay.mjs --to ws://localhost:` and query diff --git a/scripts/backup-relay.sh b/scripts/backup-relay.sh index 52f419e..da597de 100755 --- a/scripts/backup-relay.sh +++ b/scripts/backup-relay.sh @@ -20,6 +20,9 @@ export PATH="/home/sovereignsk8/.nvm/versions/node/v22.23.1/bin:$PATH" ARCHIVE_DIR="${SKATESPOTS_ARCHIVE_DIR:-$HOME/.backups/relay}" RESTIC_ENV="$HOME/.config/skatespots/restic.env" +# Optional SECOND offsite (e.g. an R2/B2 bucket) so we get true 3-2-1: local + +# CVM host + object storage. Same format as restic.env. +RESTIC_ENV_2="$HOME/.config/skatespots/restic-2.env" log() { echo "[$(date -Is)] $*"; } @@ -29,17 +32,28 @@ cd "$REPO" log "archiving the community relay…" node scripts/archive-relay.mjs -if [ -f "$RESTIC_ENV" ]; then - # shellcheck disable=SC1090 - set -a; . "$RESTIC_ENV"; set +a - if [ -z "${RESTIC_REPOSITORY:-}" ]; then - log "restic.env present but RESTIC_REPOSITORY is empty — skipping offsite copy" - exit 0 - fi - log "pushing to restic $RESTIC_REPOSITORY…" - restic backup --tag skatespots-relay "$ARCHIVE_DIR" - restic forget --tag skatespots-relay --keep-last 12 --prune - log "offsite copy done" +# Push the archive directory to every configured restic repo. Each is sourced in +# its own subshell so RESTIC_* variables don't leak between destinations. +copy_offsite() { + local envfile="$1" + [ -f "$envfile" ] || return 0 + ( + set -a; . "$envfile"; set +a + if [ -z "${RESTIC_REPOSITORY:-}" ]; then + log " $(basename "$envfile"): no RESTIC_REPOSITORY — skipping" + exit 0 + fi + log " → $RESTIC_REPOSITORY" + restic backup --tag skatespots-relay "$ARCHIVE_DIR" + restic forget --tag skatespots-relay --keep-last 12 --prune + ) +} + +if [ -f "$RESTIC_ENV" ] || [ -f "$RESTIC_ENV_2" ]; then + log "pushing offsite copies…" + copy_offsite "$RESTIC_ENV" + copy_offsite "$RESTIC_ENV_2" + log "offsite copies done" else log "no $RESTIC_ENV — archive kept local-only (set one up for a real offsite backup)" fi diff --git a/scripts/restic.env.example b/scripts/restic.env.example index 74eeb5f..49a81aa 100644 --- a/scripts/restic.env.example +++ b/scripts/restic.env.example @@ -16,6 +16,10 @@ # Configured here: the CVM host over SFTP using the `skatespots-cvm` ssh alias # (see AGENTS.md → Relay archive). # +# Optional SECOND offsite: copy this file to ~/.config/skatespots/restic-2.env +# and point it at another repo (e.g. Cloudflare R2 / Backblaze B2). backup-relay.sh +# pushes to BOTH, so you get true 3-2-1: local + CVM host + object storage. +# # One-time init, from this machine: # set -a; . ~/.config/skatespots/restic.env; set +a # restic init