# jellyfin
Runbook for the Jellyfin media server. Lives in
`stacks/media/docker-compose.yml` + the local overrides in
`stacks/media/compose.override.yml`.
See also: mercemay.top/src/homelab-compose/
## URLs
- Internal: https://jellyfin.home.arpa
- API ping: https://jellyfin.home.arpa/System/Info/Public
- Caddy log: `docker logs caddy | grep jellyfin`
## Startup checks
1. `docker compose -f stacks/media/docker-compose.yml ps jellyfin`
2. `curl -skI https://jellyfin.home.arpa/System/Info/Public` expects 200.
3. Check Dashboard > Playback > Transcoding that QSV is still selected.
## Common incidents
### Direct play fails, only transcoded
- Verify `/dev/dri/renderD128` exists inside the container:
`docker exec jellyfin ls -l /dev/dri`
- If missing, the render group changed (`cat /etc/group | grep render`)
and `compose.override.yml`'s `group_add: ["107"]` needs the new gid.
### Library scan stuck
- Check `tmpfs` mount `/tmp/jellyfin-transcode` usage:
`docker exec jellyfin df -h /tmp/jellyfin-transcode`. If full, a
failed transcode left artifacts. Restart the container to clear.
### Users cannot sign in via https://jellyfin.home.arpa
- This goes through Caddy's `forward_auth` to Authelia. Check
`auth.home.arpa` is up: `curl -sk https://auth.home.arpa/api/health`.
- Native clients (phones) use the raw IP + jellyfin port via a static
host override; they do not traverse Caddy.
## Backups
State path: `/srv/homelab/stacks/media/jellyfin/`.
- `jellyfin.db` is captured by `backup/stages/sqlite-backup.sh`.
- `config/users/` is included in `docker-volumes.sh` via the
`homelab_jellyfin_data` volume.
Restoring:
```
backup/restore/restore-from-b2.sh 20250112 sqlite
# copy restored jellyfin.sqlite into place, then:
docker compose restart jellyfin
```
## Upgrades
```
docker compose -f stacks/media/docker-compose.yml pull jellyfin
docker compose -f stacks/media/docker-compose.yml up -d jellyfin
```
Downgrade path: keep the previous image tag in a comment on the
`image:` line of the compose file before editing.