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>
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 viadev0/dev1in LXC config - Mounts:
/mnt/media_local↔/mnt/library - Public hostname:
media.hubris.network→ caddy →: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:vaapiVaapiDevice:/dev/dri/renderD128EnableHardwareEncoding:trueAllowHevcEncoding:trueAllowAv1Encoding:trueEnableTonemapping:trueHardwareDecodingCodecs: h264, hevc, vc1, vp9, av1EnableThrottling:trueEnableSegmentDeletion:true
Trickplay (/etc/jellyfin/system.xml):
EnableHwAcceleration:trueEnableHwEncoding: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
-
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 generateshttp://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 orOidChallenge()throwsArgumentNullException)
- Config:
-
Authentik OIDC provider —
Provider for Jellyfin(PK 6)- Client ID:
vt61t5Y2ZVtN6l3QjitkBvwUJjFKvSyl4TDBXcJx - Redirect URI:
https://media.hubris.network/sso/OID/redirect/Authentik - Application slug:
jellyfin
- Client ID:
-
SSO button injection —
/usr/share/jellyfin/web/sso-inject.js- Injected via
<script defer src="sso-inject.js?v=3">inindex.html - Polls for
.readOnlyContentdiv on the login page, adds "Sign in with Authentik" button linking to/sso/OID/start/Authentik - Cache-busted with
?v=Nparameter (bump on changes) - Lost on apt upgrade — re-inject the script tag and copy the JS file
after
apt-get upgrade jellyfin*
- Injected via
-
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
OidScopesmust be non-null — if the field is missing from the plugin config XML,OidChallenge()throwsSystem.ArgumentNullException. Always includeOidScopesin the provider config (even if empty array).SchemeOverride: "https"is required — without it, the plugin generateshttp://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.jsendpoint returns 404 on Jellyfin 10.11.x when the plugin is installed manually (not via Jellyfin's plugin manager). Thesso-inject.jsworkaround inindex.htmlis the fallback. - No Caddy forward-auth gate — the SSO plugin's OIDC redirect flow is
incompatible with Caddy's
import authentikforward-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
ApiKeysSQLite 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.
Related
- Caddy reverse proxy
- Media permissions
- arriman — *arr stack writes the libraries jellyfin reads
- DNS split-horizon
- Authentik admin — OIDC provider creation, SSO plugin config
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.jsin webindex.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.*.