Skip to content

erebor/apps is declared backed up in two files and backed up by nothing #484

Closed

Description

@Gerrrt

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:9100 path. 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:22 exists and does
    nothing, because TrueNAS ships SSH disabled. ADR-0016 wrote that rule for
    "prometheus pulling 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, outside backup-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-config a 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
    beyond oracle'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/media is 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

  1. added this to the Wave 3 — NAS milestone on Sep 17, 2026
  2. added
    enhancementNew feature or request
    seq/5Step 5 within its milestone; same number = can run in parallel
    mediastacks/media on smaug (VLAN 40)
    on Sep 17, 2026
  3. Gerrrt commented on Sep 19, 2026

    @Gerrrt
    OwnerAuthor

    2026-09-19 — no longer blocked on the pool, and one fact changes the shape. erebor exists and the stack runs (#522).

    The fact: jellyfin-config is not on erebor/apps. It is a Docker named volume, and TrueNAS keeps named volumes on the pool it was given for Apps, in erebor/ix-apps/docker. So the dataset §4 calls "backed up" holds the compose file and its .env and nothing Jellyfin writes. Whichever mechanism this issue picks, it also has to pick between binding /config to erebor/apps — which makes §4's table true and puts the state somewhere a ZFS snapshot or a pull can name — or reading the ix-apps dataset as it is. build-the-nas.md §4 records the discrepancy so the table is not read as describing what exists.

    Refs #484 #413

  4. added
    seq/1Step 1 within its milestone; same number = can run in parallel
    and removed
    seq/5Step 5 within its milestone; same number = can run in parallel
    on Sep 19, 2026
  5. Gerrrt commented on Sep 19, 2026

    @Gerrrt
    OwnerAuthor

    2026-09-19 — decided, built, benched; not deployed. #554 carries ADR-0045 and the mechanism, against the four checklist items:

    • Mechanism: the monitoring host pulls over the inert 99 → 40:22 pass, reading Jellyfin's /config out of the newest periodic ZFS snapshot of erebor/apps, encrypting on arrival with age, and copying the set to oracle in 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, outside age, the sentinel check and CI); and encrypting on the NAS, which ADR-0016 said and now carries a NOTE about.
    • Sentinel: ./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.
    • Where the copy lands: backups/nas/ here and backups/nas on oracle, beside the volume sets; make verify-backups proves both kinds on both sides nightly.
    • What is not covered, on the host: erebor/media, jellyfin-cache and erebor/ix-apps, in the compose file, the env example and the README, and STACK=media backup-volumes.sh --inventory now says nothing to archive rather than dying.
    • The fourth item: /config becomes 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 on erebor/apps; user frodo with 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/null proof as frodo; the migration; make backup-nas by hand, then make 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.

  6. added 5 commits that reference this issue on Sep 20, 2026
  7. Gerrrt commented on Sep 20, 2026

    @Gerrrt
    OwnerAuthor

    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 9f65fe6 and from this host:

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmediastacks/media on smaug (VLAN 40)seq/1Step 1 within its milestone; same number = can run in parallel

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions