Skip to content

Media tier: Jellyfin — placement answers the terminal-VLAN problem #138

Description

@Gerrrt

Sub-issue of #95.

What and why

Jellyfin GPL-2.0 C#/deb/Dockerawesome-selfhosted README.md:1397.

Clients exist for Roku, Android TV, iOS and Kodi, which is the property that decides this category — a media server nobody's television can reach is not a media server.

Why this is on 40 and not 99

ADR-0008 treats this as the more interesting half of the placement decision, and it is worth restating because it is easy to undo by accident:

CasaBonita (40) is terminal by design and its televisions need a media server. Any design placing the media server elsewhere has to punch a rule through that terminal property.

Putting Jellyfin with the televisions means they reach it natively. The terminal property of VLAN 40 is preserved by placement rather than by exception — no inbound rule, no hole in the segment.

The corollary is that the only new rule is 50 → 40, so a workstation on Hicks can administer the NAS and the server. Directional, trusted into less trusted, consistent with every other rule in the estate.

What it needs

  • The NAS, per Plan and build the NAS on VLAN 40 #95 — capacity and redundancy are that issue's questions, not this one's.
  • Hardware transcoding. An N100 does QSV well; without it, one 4K transcode saturates the box. Worth confirming the client mix first, because direct play needs none of it.
  • Admin credentials in secrets/*.sops.yaml.
  • A decision on whether the library is backed up at all. ADR-0008 is explicit that this data is replaceable and its loss is "annoying rather than catastrophic" — so a deliberate no is a perfectly good answer, as long as it is deliberate and written down.

The failure-domain point worth keeping

ADR-0008's compensation for running two hosts:

a failure of the media box costs a film night, and a failure of the sensitive box costs a restore — never both at once.

Anything that later couples these two tiers gives that up. Worth remembering when something proposes to share a database, a proxy or an auth layer across both.

Which VLAN this touches

🟡 40 — CasaBonita (media)
🟠 50 — Hicks (trusted) — the administrative direction

Security review

  • Does not weaken the default-deny posture between VLANs — adds 50→40, authorised by ADR-0008; document it in docs/network.md and docs/security.md as it is created, per the warning in Write a superseding ADR: 0002 says two inter-VLAN rules, there are three #104. VLAN 40 stays terminal for inbound
  • Any new credential goes in secrets/*.sops.yaml
  • Any new device is added to docs/network.md with an OUI-truncated MAC — the NAS itself

Depends on

#95 (the NAS).


Note

Status, 2026-09-17. The stack is authored. It is not deployed.

The rule this issue asks for exists. The 50→40 pass was created on
2026-09-16 and verified in position from morpheus, as two rules rather
than one with a port list: Hicks reaches 10.0.40.30 on 443 and on 8096.
443 is not the 22 ADR-0016's table names — that port assumed a box
administered over SSH, and smaug runs TrueNAS
(ADR-0040).
docs/network.md and docs/security.md were both edited the same day, which is
what the security-review box above asked for. VLAN 40's Reaches column is
unchanged: every pass reaches in.

stacks/media/
exists
, authored ahead of the pool the way stacks/sensitive was authored
ahead of trinity. Jellyfin alone — ADR-0016 builds it alone and defers Plex
(#139) against a test nobody has run. Everything non-obvious in it was read off
the pinned image on 2026-09-16 rather than out of upstream's documentation:
non-root at 65534 with /config and /cache already 0:0 777 so no chown
sidecar is needed, read_only, cap_drop: ALL, the library mounted :ro, a
curl healthcheck keyed on status code only because a fresh instance answers
200 OK with the body Degraded, and mem_limit: 2g over a measured 65 MiB
idle RSS. No reverse proxy, deliberately: the clients are televisions, and a
proxy would add a hop, a certificate every television must trust, and a second
thing to be down.

RENDER_GID=107, read off smaugstat -c '%g %G' /dev/dri/renderD128
returns 107 render.

The transcoding question this issue raised is two-thirds answered

This issue said hardware transcoding is "worth confirming". Two of the three
steps are confirmed and the third is not, and the distinction matters because
three-quarters of a condition met reads like a condition met:

  • ✅ The silicon — HD P630, Quick Sync present on Kaby Lake, Active Video: IGD
    set in the BIOS.
  • ✅ The kernel — a render node exists, which means a driver bound to the P630.
  • A container actually using it. Untested.

That last one is ADR-0040's reopen condition,
and this issue is where it gets tested — build-the-nas.md §6, after the pool.
If Quick Sync does not reach a container cleanly under TrueNAS, ADR-0040's
decision 2 reopens and the media stack leaves this repository for catalogue
apps. Getting it wrong never fails loudly: Jellyfin falls back to software
transcoding and one 4K stream saturates the box, which presents as "the film
stutters" rather than as an error. Check it before the library exists, not
after.

What is left

The two Exos X20 drives, the pool erebor, the erebor/media dataset and its
share — build-the-nas.md §1–§5 — and then §6 deploys this. The library-backup
decision this issue asks for is made: erebor/media is not backed up and
erebor/apps (Jellyfin's database and config) is, per §4, which is the
deliberate no this issue said would be a perfectly good answer.

Depends on #413, not #95, which
closed on 2026-09-04.

Activity

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/2Step 2 within its milestone; same number = can run in parallel

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions