Repository navigation
Description
build-the-nas.md
§4 splits the pool into two datasets and calls the split "the backup decision
made deliberately rather than drifted into":
| Dataset | What it holds | Backed up |
|---|---|---|
erebor/media |
films, music, the library | no |
erebor/apps |
Jellyfin's database and config | yes |
The reasoning is sound and already settled by ADR-0008: the library is
replaceable and its loss is "annoying rather than catastrophic", but the
metadata is not — watch history, resume positions, accounts, how the library is
organised. "Re-acquiring a series does not restore which episode you were on,
and that is measured in megabytes."
Nothing implements the yes. §8 of the same runbook says so: "The off-host
copy of erebor/apps, which §4 decided should exist and this runbook does not
build."
It is claimed in a second place too
stacks/media/compose.yaml:184
says of the jellyfin-config volume: "Backed up. See the mount comment above,
and §4 of build-the-nas.md for why this is the half of the tier that is."
scripts/backup-volumes.sh contains no jellyfin entry and no sentinel for it.
So two files assert a backup that no script performs, which is worse than
having no backup: the next person to read either one has no reason to look.
This is the shape #428 found in
the sensitive tier — volumes with no sentinels — arriving a second time, and it
is cheaper to fix before the data exists than after.
Why it is not simply "add it to backup-volumes.sh"
That script runs on the monitoring host, against volumes on the Docker daemon
it can see, and it verifies by decrypting — which needs the private key present.
smaug is on CasaBonita, it initiates nothing upward, and the whole estate's
relationship with it is pull. So the mechanism is a design question, not a
table entry, and it has at least three candidate answers with different costs:
- A pull over the existing
99 → 40:9100path. That rule is scoped to the
scrape port; anything else needs another rule. - The inert port-22 rule.
10.0.99.20 → 10.0.40.30:22exists and does
nothing, because TrueNAS ships SSH disabled. ADR-0016 wrote that rule for
"prometheuspulling the metadata backup" — which is exactly this job.
Switching SSH on is then a deliberate act with a written reason. - TrueNAS's own replication or cloud-sync tasks, which would put a second
backup mechanism in the estate, outsidebackup-volumes.sh's verification and
outside CI's reach — the same boundary ADR-0040 accepted for the pool layout,
and worth accepting or rejecting on purpose.
What it needs
- Pick the mechanism, and write down why the other two were not picked.
- Give
jellyfin-configa sentinel, so the claim in the compose file is
checkable rather than decorative. - Decide where the copy lands. ADR-0015's volume sets want an off-host home
beyondoracle's shelf, and this is a small amount of data, so it may
simply join what already exists rather than needing somewhere new. - Say plainly what is not covered:
erebor/mediais not backed up, on
purpose, and that should be as legible on the host as it is in §4.
Blocked on the pool — build-the-nas.md §3–§4, which waits on the two Exos
drives. Tracked under #413.
Found reconciling the tracker against the smaug build.
Corrected 2026-09-19
"Blocked on the pool" — no longer. Unblocked, still entirely true, and worse than filed: per the comment above, jellyfin-config is a Docker named volume on erebor/ix-apps/docker, not on erebor/apps, so the dataset §4 calls "backed up" holds the compose file and its .env and nothing Jellyfin writes. Meanwhile scripts/backup-volumes.sh names no media volume in SENTINEL, COMPANIONS or DISPOSABLE, and stacks/media/compose.yaml still labels jellyfin-config "Backed up".
Fourth checklist item, promoted from the comment: bind /config to a path under erebor/apps, or back up ix-apps as-is — decide which, then the copy off-host. Re-sequenced to seq/1: the highest-value unblocked item in this milestone, and one of the two things it closes on.
Activity
Gerrrt commentedon Sep 19, 2026
2026-09-19 — no longer blocked on the pool, and one fact changes the shape.
ereborexists and the stack runs (#522).The fact:
jellyfin-configis not onerebor/apps. It is a Docker named volume, and TrueNAS keeps named volumes on the pool it was given for Apps, inerebor/ix-apps/docker. So the dataset §4 calls "backed up" holds the compose file and its.envand nothing Jellyfin writes. Whichever mechanism this issue picks, it also has to pick between binding/configtoerebor/apps— which makes §4's table true and puts the state somewhere a ZFS snapshot or a pull can name — or reading theix-appsdataset as it is.build-the-nas.md§4 records the discrepancy so the table is not read as describing what exists.Refs #484 #413
Gerrrt commentedon Sep 19, 2026
2026-09-19 — decided, built, benched; not deployed. #554 carries ADR-0045 and the mechanism, against the four checklist items:
99 → 40:22pass, reading Jellyfin's/configout of the newest periodic ZFS snapshot oferebor/apps, encrypting on arrival withage, and copying the set tooraclein the same run by make backup's volume sets stay on the host they protect: ADR-0015's copy to oracle is decided and unbuilt #535's helpers. Rejected, with reasons in the ADR: a second rule on the 9100 path; TrueNAS replication/cloud-sync (smaug-initiated, outsideage, the sentinel check and CI); and encrypting on the NAS, which ADR-0016 said and now carries a NOTE about../data/jellyfin.db, read off a boot of the pinned image — it appears about thirty seconds into a first start, the WAL beside it is where the writes are, and a clean stop checkpoints it. Snapshots capture all three files at one instant, which is what makes reading one consistent.backups/nas/here andbackups/nasonoracle, beside the volume sets;make verify-backupsproves both kinds on both sides nightly.erebor/media,jellyfin-cacheanderebor/ix-apps, in the compose file, the env example and the README, andSTACK=media backup-volumes.sh --inventorynow says nothing to archive rather than dying./configbecomes a bind mount at/mnt/erebor/apps/jellyfin/config, so the dataset §4 names is the one holding the state; §6 of the runbook migrates what the named volume already holds.What is yours, from the Mac and the console —
build-the-nas.md§4.1 and §6.2, in order: the snapshot task onerebor/apps; userfrodowith the operator key; the read entry on the dataset (record what the Apps preset had set); SSH on, key-only; the host key; the tar-to-/dev/nullproof asfrodo; the migration;make backup-nasby hand, thenmake install-timers; the tripwire re-read; and the doc flip for the sentences that say "inert until §6.2". This closes on §6.2's Done block, not on the merge.Refs #554, refs #535.
feat(backup): jellyfin's state is pulled off smaug from a ZFS snapsho…
Merge pull request #554 from Gerrrt/gerrrt/erebor-apps-backup-193704
Merge pull request #561 from Gerrrt/gerrrt/nas-snapshot-child-dataset…
Merge pull request #563 from Gerrrt/gerrrt/nas-snapshot-task-done
Merge pull request #564 from Gerrrt/gerrrt/nas-set-counted-everywhere
Gerrrt commentedon Sep 20, 2026
Done when, met — closing on §6.2's Done block, as the comment above set the bar.
Read on 2026-09-20 from the tree at
9f65fe6and from this host:scripts/backup-nas.sh(feat(backup): pull Jellyfin's state off smaug from a ZFS snapshot, encrypt it here and copy it to oracle (#484) #554);/configis a bind mount onerebor/apps, migrated perbuild-the-nas.md§6.frodo, the ACL entry, SSH key-only, the host key, the tar-to-nowhere proof — all in §6.2's Done block dated 2026-09-20 (docs(nas): snapshot task and backup pull done; port 22 stops being inert everywhere it was said (#484) #563).20260920T060234Z, 76 entries,./data/jellyfin.dbpresent, copied tooracleand hashed there in the same run;make verify-backupsre-read it beside the six observability sets.systemctl list-timerson the monitoring host showshomelab-backup-nas.timer, next run Sat 2026-09-26 03:32 UTC.igc0.40at 0 packets with the pull done (§6.2 step 8).What this does not do, and never claimed to: offsite. Every copy is on one shelf, which is
roadmap.md's residual. The pool it snapshots is a mirror of one until #558 swaps the faulted Exos; that issue's checklist box for "erebor/apps copied off before the tray is touched" is ticked by this.