Build the alpha -> vlda-01 Gitea backup strategy
Implements the sketch from SYNC-PLAN.md item 2b. gitea dump (not raw rsync, to avoid grabbing the live SQLite DB mid-write) runs nightly on alpha via cron, into a dedicated read-only-chrooted SFTP account (giteabackup) reusing the existing ftp_jens/ftp_alex sshd pattern. vlda-01 pulls whatever's new via a User Scripts plugin entry (not a raw crontab - Unraid's / and /usr are RAM-backed and don't survive reboot, only /boot does), fetching only files it doesn't already have so a run after days offline catches up on everything missed. Found and fixed two real issues along the way: a default ACL on the backup directory doesn't actually grant read access to new dump files, since gitea dump creates them 600 and the resulting ACL mask neuters the inherited grant - fixed by applying the ACL explicitly per file. And the restricted account's ForceCommand internal-sftp blocks a real rsync invocation, so the transport is SFTP get, not rsync. Verified end-to-end through the actual scheduled-invocation path on both ends, including a second run correctly skipping an already-pulled file instead of re-fetching it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+7
-54
@@ -57,60 +57,13 @@ setup.** vlda-01's copy left stopped as a cold backup, not decommissioned.
|
||||
|
||||
#### 2b. Ongoing backup: `git.jayfield.org` (alpha) → `vlda-01.home.jayfield.org`
|
||||
|
||||
**Status: sketch only, not built.** Now that alpha is the canonical live
|
||||
Gitea, vlda-01's stopped copy will just get staler over time unless
|
||||
something keeps feeding it. Goal here is a **backup**, not a hot standby
|
||||
or live mirror — point-in-time recovery if alpha's Gitea is ever lost,
|
||||
not instant failover.
|
||||
|
||||
**Same network constraint as everything else in this plan**: alpha has no
|
||||
route into the home LAN (that's exactly the tunnel dependency removed
|
||||
2026-07-19), and vlda-01 isn't guaranteed to be on. So the pull has to be
|
||||
**initiated by vlda-01** whenever it happens to be up — never alpha
|
||||
reaching in.
|
||||
|
||||
**Why not a raw `rsync` of `/srv/gitea/data`**: the DB is a live SQLite
|
||||
file (`gitea.db`); rsyncing it while Gitea is writing risks grabbing it
|
||||
mid-transaction and shipping a corrupt copy. Gitea ships a purpose-built
|
||||
`gitea dump` command for exactly this (confirmed available on this
|
||||
install/version) — it produces one consistent archive (DB + repos + LFS +
|
||||
config together), which is also what Gitea's own restore procedure
|
||||
expects, rather than reinventing consistency handling.
|
||||
|
||||
**Design**:
|
||||
1. **On alpha** — a nightly cron job runs
|
||||
`docker exec -u git gitea gitea dump -f /data/backups/gitea-dump-<date>.zip --skip-index`
|
||||
(`--skip-index` drops the regenerable Bleve search index, which isn't
|
||||
needed to restore and just adds size/time) into
|
||||
`/srv/gitea/data/backups/` (a subdirectory of the same bind mount, so
|
||||
it's already host-inspectable without extra volumes). Prune to the
|
||||
last ~14 daily archives in the same job — at the repo sizes seen here
|
||||
(~4GB total) that's a bounded, comfortable footprint against alpha's
|
||||
136GB free.
|
||||
2. **On vlda-01** — a cron job (running whenever vlda-01 is powered on;
|
||||
picks up wherever it left off, same "catches up automatically"
|
||||
philosophy as the Syncthing files plan above) pulls the newest archive
|
||||
from alpha via `rsync`/`scp` over SSH into a dedicated backup directory
|
||||
(plenty of headroom on the Unraid array — 3.7TB free at last check).
|
||||
Keep its own retention window there too, independent of alpha's.
|
||||
3. **Restore path, if ever needed**: manual, deliberate — stop the target
|
||||
Gitea container, unpack the chosen dump's DB/repos/etc. into `/data`
|
||||
per Gitea's documented restore steps, restart, verify. Not automated;
|
||||
matches how every other risky operation in this repo is handled
|
||||
(careful, verified, not blind).
|
||||
4. **Explicitly out of scope for this design**: real-time replication,
|
||||
automatic failover, or DNS/traffic cutover — none of that fits a
|
||||
personal git host's actual usage pattern (a handful of commits per
|
||||
session), and the added complexity/failure surface wouldn't be worth
|
||||
it. Revisit if that ever changes.
|
||||
5. **Future consolidation**: if/when Syncthing (item 1 above) actually
|
||||
gets built, it could carry these dump archives too instead of a
|
||||
separate rsync/cron pull — one sync mechanism instead of two. Not
|
||||
worth blocking this on Syncthing existing first, though.
|
||||
|
||||
**Open question before building**: nightly cadence assumed above — confirm
|
||||
that matches how often this actually needs protecting (probably fine,
|
||||
given commit frequency, but worth a sanity check before automating it).
|
||||
**Status: built and verified, 2026-07-26 — see `README.md`'s "Gitea backup
|
||||
to vlda-01" section for the full live setup.** Point-in-time backup, not a
|
||||
hot standby/live mirror; explicitly out of scope: real-time replication,
|
||||
automatic failover, DNS/traffic cutover — none of that fits a personal
|
||||
git host's actual usage. Future consolidation candidate: if/when
|
||||
Syncthing (item 1 above) gets built, it could carry these archives too
|
||||
instead of a separate pull mechanism.
|
||||
|
||||
### 3. Jellyfin → scoping question, not yet planned
|
||||
|
||||
|
||||
Reference in New Issue
Block a user