backup-relay.sh now tunnels to the relay host's 127.0.0.1:7777 (ssh alias skatespots-cvm, override SKATESPOTS_RELAY_SSH) and falls back to the public URL, so the weekly archive no longer depends on public DNS. Verified: 115 events archived + restic push.
91 lines
3.3 KiB
Bash
Executable file
91 lines
3.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Weekly SkateSpots relay archive + optional offsite copy.
|
|
#
|
|
# Driven by the systemd user timer `skatespots-archive.timer` (install with
|
|
# scripts/install-archive-timer.sh). Local archives land in
|
|
# ~/.backups/relay; if ~/.config/skatespots/restic.env exists, the whole
|
|
# directory is pushed to a restic repository (SFTP to our own host, or any
|
|
# S3/R2/B2 store) and old snapshots are pruned. Without that file the archive is
|
|
# local-only — still useful, but not a real offsite backup.
|
|
#
|
|
# The relay lives on OUR host. The archive reaches it over an SSH tunnel to that
|
|
# host's 127.0.0.1:7777 (so it never depends on public DNS resolving from this
|
|
# machine). If the tunnel can't be established it falls back to the public URL.
|
|
# Override with SKATESPOTS_RELAY_SSH (default: the `skatespots-cvm` ssh alias)
|
|
# and SKATESPOTS_RELAY_TUNNEL_PORT (default 17777).
|
|
#
|
|
# Manual run / debug:
|
|
# scripts/backup-relay.sh
|
|
# journalctl --user -u skatespots-archive -n 50
|
|
set -euo pipefail
|
|
|
|
REPO="/home/sovereignsk8/SkateSpots"
|
|
# systemd runs with a minimal PATH; node lives under nvm here.
|
|
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"
|
|
|
|
TUNNEL_PORT="${SKATESPOTS_RELAY_TUNNEL_PORT:-17777}"
|
|
SSH_TARGET="${SKATESPOTS_RELAY_SSH:-skatespots-cvm}"
|
|
|
|
log() { echo "[$(date -Is)] $*"; }
|
|
|
|
mkdir -p "$ARCHIVE_DIR"
|
|
cd "$REPO"
|
|
|
|
# Port-open probe (uses node, which is always on PATH here).
|
|
port_open() {
|
|
node -e 'const n=require("net");const s=n.connect(+process.argv[1],"127.0.0.1");s.on("connect",()=>{s.destroy();process.exit(0)});s.on("error",()=>process.exit(1));setTimeout(()=>process.exit(1),2000)' "$1" 2>/dev/null
|
|
}
|
|
|
|
log "archiving the community relay…"
|
|
RELAY_ARG=""
|
|
TUNNEL_PID=""
|
|
ssh -N -o BatchMode=yes -o ExitOnForwardFailure=yes \
|
|
-L "127.0.0.1:${TUNNEL_PORT}:127.0.0.1:7777" "$SSH_TARGET" >/dev/null 2>&1 &
|
|
TUNNEL_PID=$!
|
|
trap 'kill "$TUNNEL_PID" 2>/dev/null || true' EXIT
|
|
for _ in 1 2 3 4 5; do
|
|
port_open "$TUNNEL_PORT" && break
|
|
sleep 1
|
|
done
|
|
if port_open "$TUNNEL_PORT"; then
|
|
RELAY_ARG="--relay ws://127.0.0.1:${TUNNEL_PORT}"
|
|
log " via SSH tunnel to $SSH_TARGET (localhost:7777)"
|
|
else
|
|
log " tunnel unavailable — using the public relay URL"
|
|
fi
|
|
|
|
# shellcheck disable=SC2086
|
|
node scripts/archive-relay.mjs $RELAY_ARG
|
|
|
|
# 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
|