jellyfin: VAAPI HW accel + Authentik SSO + resource bump (2026-07-04)
- Upgraded 10.11.8 → 10.11.11, enabled VAAPI (Radeon 760M) - Bumped to 4 cores / 8 GiB RAM / 1 GiB swap - SSO-Auth plugin v4.0.0.4 with Authentik OIDC - Removed Caddy forward-auth gate (incompatible with SSO plugin) - Updated container doc with full SSO architecture + pitfalls
This commit is contained in:
@@ -1,14 +1,17 @@
|
|||||||
# 101 — `jellyfin`
|
# 101 — `jellyfin`
|
||||||
|
|
||||||
Media server: serves the movies / TV / anime / music / audiobooks / podcasts libraries from `/mnt/library` to LAN clients.
|
Media server: serves the movies / TV / anime / music libraries from `/mnt/library` to LAN clients. Hardware transcoding via AMD Radeon 760M VAAPI. Authentik SSO via OIDC.
|
||||||
|
|
||||||
## At a glance
|
## At a glance
|
||||||
- **Hostname:** `jellyfin`
|
- **Hostname:** `jellyfin`
|
||||||
- **IP:** `192.168.8.206`
|
- **IP:** `192.168.8.206`
|
||||||
- **Privilege:** **unprivileged** + idmap (so it can write to the `media` group on `/mnt/library`)
|
- **Privilege:** **unprivileged** + idmap (so it can write to the `media` group on `/mnt/library`)
|
||||||
- **Resources:** 2 cores / 4 GiB RAM / 16 GiB rootfs
|
- **Resources:** 4 cores / 8 GiB RAM / 1 GiB swap / 16 GiB rootfs
|
||||||
|
- **GPU:** `/dev/dri/renderD128` (AMD Radeon 760M, RDNA 3) passed via `dev0` in LXC config
|
||||||
- **Mounts:** `/mnt/library` ↔ `/mnt/library`
|
- **Mounts:** `/mnt/library` ↔ `/mnt/library`
|
||||||
- **Public hostname:** [`media.hubris.network`](../infrastructure/dns.md) → [caddy](121-caddy.md) → `:8096`
|
- **Public hostname:** [`media.hubris.network`](../infrastructure/dns.md) → [caddy](121-caddy.md) → `:8096`
|
||||||
|
- **Version:** Jellyfin 10.11.11 (apt package, Ubuntu 24.04 noble repo)
|
||||||
|
- **FFmpeg:** jellyfin-ffmpeg7 7.1.4
|
||||||
|
|
||||||
## Service / port map
|
## Service / port map
|
||||||
|
|
||||||
@@ -16,6 +19,106 @@ Media server: serves the movies / TV / anime / music / audiobooks / podcasts lib
|
|||||||
| -------- | ------ | ----- |
|
| -------- | ------ | ----- |
|
||||||
| jellyfin | `:8096` | HTTP (caddy terminates TLS) |
|
| jellyfin | `:8096` | HTTP (caddy terminates TLS) |
|
||||||
|
|
||||||
|
## Hardware acceleration (VAAPI)
|
||||||
|
|
||||||
|
GPU is passed through to the LXC via `dev0: /dev/dri/renderD128,gid=993` in
|
||||||
|
`/etc/pve/lxc/101.conf`. The `jellyfin` user is in the `render` (GID 993) and
|
||||||
|
`video` groups inside the container.
|
||||||
|
|
||||||
|
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](https://github.com/9p4/jellyfin-plugin-sso)
|
||||||
|
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](../devops/homelab-authentik-admin/references/jellyfin-sso-plugin.md))
|
||||||
|
- `OidScopes`: `["email"]` (openid+profile added by default by the plugin;
|
||||||
|
must be non-null or `OidChallenge()` throws `ArgumentNullException`)
|
||||||
|
|
||||||
|
2. **Authentik OIDC provider** — `Provider 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:
|
||||||
|
```caddy
|
||||||
|
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:
|
||||||
|
```sql
|
||||||
|
INSERT INTO ApiKeys VALUES (1, '2026-07-04', '2026-07-04', 'setup', 'jf-setup-key-...');
|
||||||
|
```
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
Member of the [media GID 10000](../infrastructure/media-permissions.md) standard. Service user `jellyfin` is in the `media` group inside the container; idmap block in `/etc/pve/lxc/101.conf` maps in-container GID 10000 to host GID 10000.
|
Member of the [media GID 10000](../infrastructure/media-permissions.md) standard. Service user `jellyfin` is in the `media` group inside the container; idmap block in `/etc/pve/lxc/101.conf` maps in-container GID 10000 to host GID 10000.
|
||||||
|
|
||||||
@@ -24,9 +127,23 @@ Member of the [media GID 10000](../infrastructure/media-permissions.md) standard
|
|||||||
- [Media permissions](../infrastructure/media-permissions.md)
|
- [Media permissions](../infrastructure/media-permissions.md)
|
||||||
- [arriman](122-arriman.md) — \*arr stack writes the libraries jellyfin reads
|
- [arriman](122-arriman.md) — \*arr stack writes the libraries jellyfin reads
|
||||||
- [DNS split-horizon](../infrastructure/dns.md)
|
- [DNS split-horizon](../infrastructure/dns.md)
|
||||||
|
- [Authentik admin](../devops/homelab-authentik-admin/SKILL.md) — OIDC provider creation, SSO plugin config
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### 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
|
### 2026-04-28 — wiki entry created
|
||||||
Initial documentation. No config changes.
|
Initial documentation. No config changes.
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ hosts:
|
|||||||
fqdn: jellyfin
|
fqdn: jellyfin
|
||||||
mounts:
|
mounts:
|
||||||
- /mnt/library
|
- /mnt/library
|
||||||
|
notes:
|
||||||
|
- Jellyfin 10.11.11 with VAAPI hardware acceleration (AMD Radeon 760M)
|
||||||
|
- 4 cores / 8 GiB RAM / 1 GiB swap (bumped from 2/4/512 on 2026-07-04)
|
||||||
|
- SSO-Auth plugin v4.0.0.4 with Authentik OIDC (no Caddy forward-auth gate)
|
||||||
|
- GPU passed via dev0: /dev/dri/renderD128,gid=993
|
||||||
age_pubkey: ''
|
age_pubkey: ''
|
||||||
nfs-export:
|
nfs-export:
|
||||||
kind: lxc
|
kind: lxc
|
||||||
|
|||||||
Reference in New Issue
Block a user