feat(backup): rsync --link-dest off-host transport, restore docs (#41) #45

Merged
libretech merged 1 commits from feat/backup-rsync-linkdest into main 2026-04-29 15:17:43 +02:00
Owner

Closes most of #41. Operator's choice of off-host target is the only remaining open item; until that lands the script and timer are useful in local-only mode.

Summary

  • `scripts/backup.sh` gains a second off-host transport: `BACKUP_REMOTE_RSYNC`. Each run rsyncs the new archive into `/YYYY-MM-DD/` at the target with `--link-dest=..//`, so unchanged archives become hard links. Daily cost = (size of changed bytes) instead of (size of full archive). `BACKUP_REMOTE_SSH_KEY` lets the rsync ssh leg use a dedicated identity for restricted accounts (rsync.net etc.).
  • `BACKUP_REMOTE` (rclone, object-store transport) stays — the two transports compose, so an operator can run both in parallel.
  • `scripts/librenotes-backup.timer` moves to `OnCalendar=--* 03:00:00 Europe/Berlin` (was 03:17 UTC) per the issue.
  • `docs/operations.md` documents:
    • the rsync vs rclone trade-off,
    • a four-step restore procedure (parallel stack first, atomic swap second) with exact commands,
    • and the `.bak-*` rollback path if the swap fails.

Verification

  • `bash -n scripts/backup.sh` parses.
  • `scripts/backup.sh` is unchanged when no `BACKUP_REMOTE*` is set; existing local-disk-only deployments keep working.

Out of scope

  • Picking the actual off-host target (rsync.net vs B2 vs another VPS) is the operator's call and stays in #41.
Closes most of #41. Operator's choice of off-host target is the only remaining open item; until that lands the script and timer are useful in local-only mode. ## Summary - \`scripts/backup.sh\` gains a second off-host transport: \`BACKUP_REMOTE_RSYNC\`. Each run rsyncs the new archive into \`<root>/YYYY-MM-DD/\` at the target with \`--link-dest=../<previous-day>/\`, so unchanged archives become hard links. Daily cost = (size of changed bytes) instead of (size of full archive). \`BACKUP_REMOTE_SSH_KEY\` lets the rsync ssh leg use a dedicated identity for restricted accounts (rsync.net etc.). - \`BACKUP_REMOTE\` (rclone, object-store transport) stays — the two transports compose, so an operator can run both in parallel. - \`scripts/librenotes-backup.timer\` moves to \`OnCalendar=*-*-* 03:00:00 Europe/Berlin\` (was 03:17 UTC) per the issue. - \`docs/operations.md\` documents: - the rsync vs rclone trade-off, - a four-step restore procedure (parallel stack first, atomic swap second) with exact commands, - and the \`.bak-*\` rollback path if the swap fails. ## Verification - \`bash -n scripts/backup.sh\` parses. - \`scripts/backup.sh\` is unchanged when no \`BACKUP_REMOTE*\` is set; existing local-disk-only deployments keep working. ## Out of scope - Picking the actual off-host target (rsync.net vs B2 vs another VPS) is the operator's call and stays in #41.
libretech added 1 commit 2026-04-29 15:17:33 +02:00
backup.sh now supports BACKUP_REMOTE_RSYNC alongside BACKUP_REMOTE.
The rsync path writes <root>/YYYY-MM-DD/<archive> on the target with
--link-dest pointing at the previous day's directory, so unchanged
archives become hard links and daily snapshots cost almost zero
extra bytes. BACKUP_REMOTE_SSH_KEY routes the rsync ssh leg to a
dedicated identity (e.g. rsync.net restricted accounts).

Timer moved to 03:00 Europe/Berlin (was 03:17 UTC) per #41.

docs/operations.md: full restore procedure (parallel stack first,
then atomic swap) plus the rsync vs rclone trade-off. Closes most
of #41 — the only remaining task is the operator's choice of
off-host target.
libretech merged commit 2c20edbe4e into main 2026-04-29 15:17:43 +02:00
Sign in to join this conversation.