version: 1 documents: - slug: containers/101-jellyfin title: 101 — `jellyfin` content: "# 101 — `jellyfin`\n\nMedia 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.\n\n## At a glance\n-\ \ **Host:** **strong** (migrated from hubris 2026-07-05)\n- **IP:** `192.168.8.246`\n- **Privilege:** privileged (recreated\ \ on strong as priv)\n- **Resources:** 4 cores / 8 GiB RAM / 1 GiB swap / 16 GiB rootfs\n- **GPU:** `/dev/dri/renderD128`\ \ + `/dev/dri/card0` (AMD Radeon 680M iGPU + RX 7600 dGPU) passed via `dev0` / `dev1` in LXC config\n- **Mounts:** `/mnt/media_local`\ \ ↔ `/mnt/library`\n- **Public hostname:** [`media.hubris.network`](../infrastructure/dns.md) → [caddy](121-caddy.md)\ \ → `:8096`\n- **Version:** Jellyfin 10.11.11 (apt package, Ubuntu 24.04 noble repo)\n- **FFmpeg:** jellyfin-ffmpeg7 7.1.4\n\ \n## Service / port map\n\n| Service | Listen | Notes |\n| -------- | ------ | ----- |\n| jellyfin | `:8096` | HTTP (caddy\ \ terminates TLS) |\n\n## Hardware acceleration (VAAPI)\n\nGPU is passed through to the LXC via `dev0: /dev/dri/renderD128,gid=993`\ \ and\n`dev1: /dev/dri/card0,gid=44` in\n`/etc/pve/lxc/101.conf` (strong). The `jellyfin` user is in the `render` (GID\ \ 993) and\n`video` groups inside the container.\n\n| GPU | Model | Role |\n|-----|-------|------|\n| Radeon 680M | iGPU\ \ (AMD Ryzen 7 PRO 6850U) | Primary VAAPI encoder/decoder |\n| RX 7600 | dGPU (add-in) | Secondary transcode, HEVC/AV1\ \ encoding |\n\nEncoding settings (`/etc/jellyfin/encoding.xml`):\n- `HardwareAccelerationType`: `vaapi`\n- `VaapiDevice`:\ \ `/dev/dri/renderD128`\n- `EnableHardwareEncoding`: `true`\n- `AllowHevcEncoding`: `true`\n- `AllowAv1Encoding`: `true`\n\ - `EnableTonemapping`: `true`\n- `HardwareDecodingCodecs`: h264, hevc, vc1, vp9, av1\n- `EnableThrottling`: `true`\n-\ \ `EnableSegmentDeletion`: `true`\n\nTrickplay (`/etc/jellyfin/system.xml`):\n- `EnableHwAcceleration`: `true`\n- `EnableHwEncoding`:\ \ `true`\n\n## Authentik SSO (OIDC)\n\nJellyfin uses the [SSO-Auth plugin](https://github.com/9p4/jellyfin-plugin-sso)\n\ v4.0.0.4 for Authentik OIDC login. No Caddy forward-auth gate — the SSO plugin\nhandles auth directly via OIDC redirect\ \ flow.\n\n### Architecture\n\n```\nUser → media.hubris.network → Caddy (TLS, no forward-auth) → Jellyfin :8096\n \ \ ↓\n Login\ \ page with \"Sign in with Authentik\" button\n ↓ (click)\n\ \ /sso/OID/start/Authentik\n \ \ ↓ (302 redirect)\n auth.hubris.network OIDC\n\ \ ↓ (login)\n \ \ /sso/OID/redirect/Authentik?code=...&state=...\n \ \ ↓\n Jellyfin SSO plugin validates token → logged in\n```\n\n\ ### Components\n\n1. **SSO-Auth plugin** — installed at `/var/lib/jellyfin/plugins/SSO-Auth_4.0.0.4/`\n - Config: `/var/lib/jellyfin/plugins/configurations/SSO-Auth.xml`\n\ \ - Provider name: `Authentik`\n - OIDC endpoint: `https://auth.hubris.network/application/o/jellyfin/`\n - `SchemeOverride`:\ \ `https` (required — without it, plugin generates\n `http://` redirect URIs that Authentik rejects)\n - `EnableAuthorization`:\ \ `false` (prevents plugin from overwriting admin\n permissions on each SSO login — see\n [jellyfin-sso-plugin](../../../devops/homelab-authentik-admin/references/jellyfin-sso-plugin.md))\n\ \ - `OidScopes`: `[\"email\"]` (openid+profile added by default by the plugin;\n must be non-null or `OidChallenge()`\ \ throws `ArgumentNullException`)\n\n2. **Authentik OIDC provider** — `Provider for Jellyfin` (PK 6)\n - Client ID:\ \ `vt61t5Y2ZVtN6l3QjitkBvwUJjFKvSyl4TDBXcJx`\n - Redirect URI: `https://media.hubris.network/sso/OID/redirect/Authentik`\n\ \ - Application slug: `jellyfin`\n\n3. **SSO button injection** — `/usr/share/jellyfin/web/sso-inject.js`\n - Injected\ \ via `