Files
oikos/knowledge/wiki/containers/101-jellyfin.md
dtoro 8a6422bd7d docs: move narrative wiki under knowledge/wiki/ (phase 3)
Problem: node and cross-cutting narratives lived at the repo root
(containers/, vms/, infrastructure/, host .md files), interleaved with the
machine-readable substrate.

Change:
- Move containers/ -> knowledge/wiki/containers/, vms/ -> knowledge/wiki/vms/,
  infrastructure/ -> knowledge/wiki/infrastructure/, hosts/{hubris,strong}.md ->
  knowledge/wiki/hosts/, infrastructure/references/ -> knowledge/sources/references/,
  GLOSSARY.md -> knowledge/GLOSSARY.md.
- Add knowledge/{index.md,log.md,sources/index.md} scaffolding.
- Rewrite all relative links repo-wide via a path-resolving mapper (inbound +
  outbound + between-moved-files), including .hermes/, runbooks, operations,
  investigations, plans, README, AGENTS.
- Repoint inventory.yaml doc_page fields and regenerate hosts/*.yaml (which
  embed doc_page); update oikos/gen-topology.py output path, candidate doc
  paths, and footer links; update code-comment doc paths.

Substrate untouched in place: inventory.yaml, hosts/*.yaml (regenerated,
idempotent), oikos/ code, mcp/, secrets/, bin/.

Verification:
- Logical broken-link set identical to pre-move baseline (net 128 -> 127; the
  topology regen fixed one, introduced none). Remaining are pre-existing refs
  to destroyed/archived nodes, out of scope for this move.
- gen-topology.py --check exit 0 (in sync); cards carry knowledge/wiki/ doc paths.
- build_host_files.py idempotent; all inventory doc_page targets resolve.
- MCP contract verified: get_page/search_docs/get_changelog resolve moved pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:35:23 +02:00

8.0 KiB

101 — jellyfin

Media server: serves the movies / TV / anime / music libraries from /mnt/media_local to LAN clients. Hardware transcoding via AMD Radeon 680M + RX 7600 VAAPI. Authentik SSO via OIDC.

At a glance

  • Host: strong (migrated from hubris 2026-07-05)
  • IP: 192.168.8.246
  • Privilege: privileged (recreated on strong as priv)
  • Resources: 4 cores / 8 GiB RAM / 1 GiB swap / 16 GiB rootfs
  • GPU: /dev/dri/renderD128 + /dev/dri/card0 (AMD Radeon 680M iGPU + RX 7600 dGPU) passed via dev0 / dev1 in LXC config
  • Mounts: /mnt/media_local/mnt/library
  • Public hostname: media.hubris.networkcaddy:8096
  • Version: Jellyfin 10.11.11 (apt package, Ubuntu 24.04 noble repo)
  • FFmpeg: jellyfin-ffmpeg7 7.1.4

Service / port map

Service Listen Notes
jellyfin :8096 HTTP (caddy terminates TLS)

Hardware acceleration (VAAPI)

GPU is passed through to the LXC via dev0: /dev/dri/renderD128,gid=993 and dev1: /dev/dri/card0,gid=44 in /etc/pve/lxc/101.conf (strong). The jellyfin user is in the render (GID 993) and video groups inside the container.

GPU Model Role
Radeon 680M iGPU (AMD Ryzen 7 PRO 6850U) Primary VAAPI encoder/decoder
RX 7600 dGPU (add-in) Secondary transcode, HEVC/AV1 encoding

Encoding settings (/etc/jellyfin/encoding.xml):

  • HardwareAccelerationType: vaapi
  • VaapiDevice: /dev/dri/renderD128
  • EnableHardwareEncoding: true
  • AllowHevcEncoding: true
  • AllowAv1Encoding: true
  • EnableTonemapping: true
  • HardwareDecodingCodecs: h264, hevc, vc1, vp9, av1
  • EnableThrottling: true
  • EnableSegmentDeletion: true

Trickplay (/etc/jellyfin/system.xml):

  • EnableHwAcceleration: true
  • EnableHwEncoding: true

Authentik SSO (OIDC)

Jellyfin uses the SSO-Auth plugin v4.0.0.4 for Authentik OIDC login. No Caddy forward-auth gate — the SSO plugin handles auth directly via OIDC redirect flow.

Architecture

User → media.hubris.network → Caddy (TLS, no forward-auth) → Jellyfin :8096
                                                                ↓
                                                    Login page with "Sign in with Authentik" button
                                                                ↓ (click)
                                                    /sso/OID/start/Authentik
                                                                ↓ (302 redirect)
                                                    auth.hubris.network OIDC
                                                                ↓ (login)
                                                    /sso/OID/redirect/Authentik?code=...&state=...
                                                                ↓
                                                    Jellyfin SSO plugin validates token → logged in

Components

  1. SSO-Auth plugin — installed at /var/lib/jellyfin/plugins/SSO-Auth_4.0.0.4/

    • Config: /var/lib/jellyfin/plugins/configurations/SSO-Auth.xml
    • Provider name: Authentik
    • OIDC endpoint: https://auth.hubris.network/application/o/jellyfin/
    • SchemeOverride: https (required — without it, plugin generates http:// redirect URIs that Authentik rejects)
    • EnableAuthorization: false (prevents plugin from overwriting admin permissions on each SSO login — see jellyfin-sso-plugin)
    • OidScopes: ["email"] (openid+profile added by default by the plugin; must be non-null or OidChallenge() throws ArgumentNullException)
  2. Authentik OIDC providerProvider for Jellyfin (PK 6)

    • Client ID: vt61t5Y2ZVtN6l3QjitkBvwUJjFKvSyl4TDBXcJx
    • Redirect URI: https://media.hubris.network/sso/OID/redirect/Authentik
    • Application slug: jellyfin
  3. SSO button injection/usr/share/jellyfin/web/sso-inject.js

    • Injected via <script defer src="sso-inject.js?v=3"> in index.html
    • Polls for .readOnlyContent div on the login page, adds "Sign in with Authentik" button linking to /sso/OID/start/Authentik
    • Cache-busted with ?v=N parameter (bump on changes)
    • Lost on apt upgrade — re-inject the script tag and copy the JS file after apt-get upgrade jellyfin*
  4. Caddy config — no forward-auth gate for media.hubris.network:

    media.hubris.network {
        tls { dns ionos {env.IONOS_AUTH_API_TOKEN} }
        reverse_proxy 192.168.8.206:8096
    }
    

Known issues / pitfalls

  • OidScopes must be non-null — if the field is missing from the plugin config XML, OidChallenge() throws System.ArgumentNullException. Always include OidScopes in the provider config (even if empty array).
  • SchemeOverride: "https" is required — without it, the plugin generates http:// redirect URIs (from the internal HTTP listener). Authentik rejects them with "Redirect URI Error".
  • SSO button JS is not served by the plugin — the __plugin/SSO-Auth.js endpoint returns 404 on Jellyfin 10.11.x when the plugin is installed manually (not via Jellyfin's plugin manager). The sso-inject.js workaround in index.html is the fallback.
  • No Caddy forward-auth gate — the SSO plugin's OIDC redirect flow is incompatible with Caddy's import authentik forward-auth. If both are enabled, the forward-auth intercepts the OIDC callback and breaks the flow. Use one or the other, not both. SSO plugin (OIDC redirect) is preferred.
  • API key for setup — a temp API key can be inserted directly into the ApiKeys SQLite table for automated configuration:
    INSERT INTO ApiKeys VALUES (1, '2026-07-04', '2026-07-04', 'setup', 'jf-setup-key-...');
    

Permissions

Member of the media GID 10000 standard. Service user jellyfin is in the media group inside the container; /mnt/media_local on strong's ludo-lvm is owned root:media with mode 2775.

Changelog

2026-07-06 — wiki: IP, host, GPU, mount path updated for strong migration

Updated At-a-glance: IP 206→246, host hubris→strong, mount /mnt/library→/mnt/media_local, GPU Radeon 760M→680M+RX7600, privilege unpriv→priv. Permissions section updated. Changelog entry in 122-arriman.md updated similarly.

2026-07-04 — VAAPI hardware acceleration + Authentik SSO + resource bump

  • Upgraded Jellyfin 10.11.8 → 10.11.11 (purge + reinstall to fix DB migration bug)
  • Enabled VAAPI hardware acceleration (Radeon 760M): h264/hevc/vc1/vp9/av1 decode + encode
  • Bumped resources: 2→4 cores, 4→8 GiB RAM, 512→1024 MiB swap
  • Enabled trickplay HW acceleration + throttling + segment deletion
  • Installed SSO-Auth plugin v4.0.0.4 with Authentik OIDC provider
  • Configured SchemeOverride: https, OidScopes: ["email"], EnableAuthorization: false
  • Injected SSO button via sso-inject.js in web index.html
  • Removed Caddy forward-auth gate (incompatible with SSO plugin OIDC flow)
  • Database was wiped during cache relocation attempt — no LVM snapshot existed. All watch states, user accounts, and library configs lost. Libraries re-added via setup wizard.

2026-04-28 — wiki entry created

Initial documentation. No config changes.

2026-04-20 — joined the media GID 10000 standard

Idmap block applied; in-container media group at GID 10000 mapped to host GID 10000. See media permissions. Config backup: /root/101.conf.bak.*.