Repository navigation
Backups: plain-file NAS mirror + read-only archive copy - #38
Merged
Merged
Conversation
The restic sidecar stores encrypted chunks, so nothing on the NAS can be opened or run. backup.sh now optionally (BACKUP_MIRROR_PATH) keeps a plain-file mirror beside it: rclone over the same SFTP account, media first and then a rollback-journal copy of the database, plus a MIRROR_INFO with the time and migration revision. READ_ONLY=true opens the database mode=ro with a fresh connection per session (the mirror renames a new file in under it), refuses every non-GET with a read_only error, starts no workers and skips migrations. READ_ONLY_USER replaces sign-in in an archive and is refused without READ_ONLY. The frontend shows a banner and drops sign-out. ops/archive/ holds the Container Manager project for the Synology, and ops/backup/README.md is now one from-scratch procedure: NAS, restic, mirror, restore. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWoa1a1upTria7ntq56x3B
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWoa1a1upTria7ntq56x3B
…ction Confirmed against gecko-notes' ops/backup: its account already writes to GeckoNotes, with its repository at /GeckoNotes/restic, so GAM beside it under /GeckoNotes/gam/ needs no NAS change at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWoa1a1upTria7ntq56x3B
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWoa1a1upTria7ntq56x3B
davior
marked this pull request as ready for review
October 22, 2026 01:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The restic sidecar stores encrypted, deduplicated chunks, so nothing on the NAS can be opened or run. This adds a plain-file mirror next to it, plus a read-only copy of GAM that runs from that mirror in Synology's Container Manager, with no dependency on production or Notes.
Mirror (
ops/backup)BACKUP_MIRROR_PATH, and runs in the same scheduled run after restic. If it's empty, the mirror stays off.sync, so deletions propagate. restic keeps the history.MIRROR_INFO, with the time and alembic revision..partialfiles are excluded.Read-only mode (backend + frontend)
READ_ONLY=true:mode=ro, withNullPoolso each session sees the newly swapped-in file;{"detail":{"code":"read_only",…}};entrypoint.sh.READ_ONLY_USER(an id or username) replaces sign-in. Settings refuse it unlessREAD_ONLYis also set, andcurrent_userchecks both again./api/configgainsread_only. The shell shows an amber banner and hides sign-out.Deployment / docs
ops/archive/holds a standalone compose project for Container Manager: read-only mounts, its own network, and a distinct JWT secret.ops/archive/README.mdis the NAS walkthrough.ops/backup/README.mdis now one from-scratch procedure: NAS → restic → mirror → restore. The deadbackup-strategy.mdreference is gone.known_hosts, and puts GAM under/GeckoNotes/gam/{restic,mirror}, next to Notes'/GeckoNotes/restic, so the NAS needs no changes. Checked against gecko-notes'ops/backup.BACKUP_SFTP_REMOTE_PATHis now/GAM/restic. The old/gamdefault was the root of DSM's chroot, where the backup account can't write.Testing
pytest -q: 1272 passed, including newtests/test_read_only.py.npm test: 395 passed.npm run buildis clean.backup.shwas run end to end against rclone'slocalbackend..partialwas excluded, the DB came out indeletemode and openedmode=ro,MIRROR_INFOwas written, and a deletion propagated on the second run.READ_ONLY=trueagainst a migrated DB on a read-only directory./api/mereturned the fixed user, a write got 403read_only, and a DB swapped in by rename was picked up without a restart.🤖 Generated with Claude Code
https://claude.ai/code/session_01XWoa1a1upTria7ntq56x3B