All in-repo path references (AGENTS.md, README, old scripts, report artifacts,
test code paths) rewritten in the same commit; focused-test map extended for
.gitignore, old/scripts/*, dankclaw/comfyui/*, and report/* per this repo's
own convention ('add one before committing'). Obsidian wikilinks are
title-based and unaffected.
174 lines
6.5 KiB
Markdown
174 lines
6.5 KiB
Markdown
# Jellyfin
|
||
|
||
Jellyfin is a free, open-source media server and suite of applications for organizing, managing, and streaming personal media collections (movies, TV shows, music, photos) to networked devices. It is a community fork of Emby, written in C# (.NET), and uses FFmpeg for transcoding.
|
||
|
||
**Host:** Dankserver — **Hostname:** `jellyfin.dankserver.local` — **Docs:** https://jellyfin.org
|
||
|
||
## Facts
|
||
|
||
| Item | Value |
|
||
|------|-------|
|
||
| Latest version | Check https://jellyfin.org/downloads |
|
||
| Image | `jellyfin/jellyfin:latest` (Docker Hub) or `ghcr.io/jellyfin/jellyfin` |
|
||
| Base | Debian-based |
|
||
| Primary port | 8096 (HTTP, web UI + API) |
|
||
| HTTPS port | 8920 (optional) |
|
||
| Client discovery | 7359/udp |
|
||
| DLNA | 1900/udp (optional) |
|
||
| GPU passthrough | `/dev/dri` (Intel QSV / AMD VA-API) or NVIDIA NVENC |
|
||
| License | MIT |
|
||
|
||
## Architecture
|
||
|
||
```mermaid
|
||
graph LR
|
||
U[User] --> C[Caddy :80/:443]
|
||
C --> J[Jellyfin :8096]
|
||
J --> Lib[/media/movies]
|
||
J --> Lib2[/media/shows]
|
||
J --> Lib3[/media/music]
|
||
J --> Conf[Jellyfin config]
|
||
J --> Cache[Jellyfin cache]
|
||
```
|
||
|
||
## Docker Compose
|
||
|
||
```yaml
|
||
services:
|
||
jellyfin:
|
||
image: jellyfin/jellyfin:latest
|
||
container_name: jellyfin
|
||
restart: unless-stopped
|
||
user: "1000:1000"
|
||
ports:
|
||
- "8096:8096/tcp"
|
||
- "8920:8920/tcp"
|
||
- "7359:7359/udp"
|
||
- "1900:1900/udp"
|
||
environment:
|
||
- JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096
|
||
- DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
|
||
volumes:
|
||
- /opt/jellyfin/config:/config
|
||
- /opt/jellyfin/cache:/cache
|
||
- /mnt/media/movies:/data/movies:ro
|
||
- /mnt/media/shows:/data/shows:ro
|
||
devices:
|
||
- /dev/dri:/dev/dri
|
||
group_add:
|
||
- "992" # Host render group GID — verify with `getent group render`
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
```
|
||
|
||
## Caddy Configuration
|
||
|
||
```caddy
|
||
jellyfin.dankserver.local {
|
||
reverse_proxy 127.0.0.1:8096
|
||
|
||
transport http {
|
||
versions h2c 1.1
|
||
}
|
||
}
|
||
```
|
||
|
||
Set **Base URL** to `/` (or the path you configure) in Jellyfin Dashboard → Networking. Add `127.0.0.1` to **Known Proxies**.
|
||
|
||
## Storage
|
||
|
||
| Mount | Purpose | Size Estimate |
|
||
|-------|---------|---------------|
|
||
| `/opt/jellyfin/config` | SQLite database, settings, cached images | 10–100 GB |
|
||
| `/opt/jellyfin/cache` | Transcoding segments, extracted posters | Self-cleaning per session |
|
||
|
||
The database must be on local storage (SSD/NVMe preferred). Media libraries can be on NFS/mergerfs. If media is on NFS, set `DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true`.
|
||
|
||
## Authentication
|
||
|
||
- **Built-in auth (default):** Per-user libraries, parental controls, max bitrate limits. Manage via Dashboard → Users.
|
||
- **Caddy basic auth:** Single login layer. Does not integrate with per-user Jellyfin permissions.
|
||
- **LDAP/OIDC:** Available via plugins (LDAP-Auth, Jellyfin SSO). Integrates with Authentik, Keycloak, etc.
|
||
|
||
For Dankserver, built-in auth is recommended. Use Caddy basic auth on top for external access.
|
||
|
||
## Metadata Scraping
|
||
|
||
| Provider | Content | Type |
|
||
|----------|---------|------|
|
||
| TheMovieDb (TMDb) | Movies, TV shows, posters, fan art, overviews | Default |
|
||
| OMDb API | Movies only, English metadata | Default |
|
||
| TheTVDB | TV shows, episodes | Plugin |
|
||
| fanart.tv | Extra artwork, banners, thumbnails | Plugin |
|
||
| AniDB | Anime metadata | Plugin |
|
||
| MusicBrainz | Music metadata | Plugin |
|
||
| Open Subtitles | Subtitle downloads | Plugin |
|
||
| Intro Skipper | TV show intro detection | Plugin |
|
||
|
||
## Clients
|
||
|
||
| Platform | App | Quality |
|
||
|----------|-----|---------|
|
||
| Web | Jellyfin Web | Excellent |
|
||
| Android | Jellyfin (Google Play / F-Droid) | Excellent |
|
||
| Android TV / Fire TV | Jellyfin | Good |
|
||
| iOS / iPadOS | Swiftfin (third-party) | Good |
|
||
| Desktop | Jellyfin Media Player (mpv-based) | Excellent |
|
||
| Roku | Jellyfin (Channel Store) | Good |
|
||
| Kodi | Jellyfin addon | Excellent |
|
||
| Samsung/LG Smart TVs | TV browser | Fair |
|
||
|
||
## Jellyfin vs Plex
|
||
|
||
| Feature | Jellyfin | Plex |
|
||
|---------|----------|------|
|
||
| Cost | Free, no tiers | Free core; Plex Pass ($5/mo or $120 lifetime) |
|
||
| License | MIT | Proprietary |
|
||
| Account required | No | Yes |
|
||
| Hardware transcoding | Free | Plex Pass required |
|
||
| Mobile sync | Free | Plex Pass |
|
||
| Live TV / DVR | Free | Plex Pass |
|
||
| Client apps | Good, improving | Excellent, widest device support |
|
||
|
||
Run Jellyfin alongside Plex for an incremental migration. Point Jellyfin at the same media folders as Plex. Watch history and metadata will not transfer cleanly.
|
||
|
||
## Resource Requirements
|
||
|
||
- **Idle / Direct Play:** ~200–500 MB RAM, <5% CPU. Negligible.
|
||
- **1080p transcode (CPU):** 40–60% CPU on a modern multi-core CPU.
|
||
- **1080p transcode (with QSV):** 3–5% CPU.
|
||
- **4K HDR transcode (with QSV):** 5–15% CPU.
|
||
- **Minimum host RAM:** 4 GB. 8 GB comfortable for transcoding.
|
||
|
||
## Deployment Checklist
|
||
|
||
1. Verify GPU on host: `ls -l /dev/dri/`, `lspci | grep -i vga`, `getent group render`.
|
||
2. Install media drivers: `sudo apt install intel-media-va-driver-non-free vainfo intel-gpu-tools`.
|
||
3. Create directories: `/opt/jellyfin/config`, `/opt/jellyfin/cache`.
|
||
4. Write compose file, verify device and GID.
|
||
5. Deploy: `podman compose up -d`.
|
||
6. Test GPU passthrough: `podman exec jellyfin /usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128`.
|
||
7. Configure Caddy reverse proxy. Set Known Proxies in Jellyfin.
|
||
8. Add media libraries in Dashboard.
|
||
9. Install plugins: Open Subtitles, fanart.tv, Intro Skipper.
|
||
10. Test playback on Android/Chrome.
|
||
|
||
## Gotchas
|
||
|
||
- **GPU passthrough silently failing:** `/dev/dri` must be passed and the correct render node used. Verify with `vainfo` inside the container.
|
||
- **Wrong render group GID:** Common GID is 992, but varies per host. Run `getent group render` to find it.
|
||
- **Subtitle burn-in triggers full transcode:** PGS (image-based) subtitles force full video transcoding. SRT/ASS (text-based) play fine.
|
||
- **Database on NFS:** SQLite on network storage causes slow startup and corruption risk. Keep `/config` on local storage.
|
||
- **Client bitrate limit too low:** Many clients default to 20 Mbps. Set Max Streaming Bitrate to Original or Maximum.
|
||
- **Naming convention mismatches:** Non-standard folder/file names cause missing metadata. Use `Movie Title (Year)` for movies and `Show Name/Season 01/Show Name S01E01.mkv` for TV.
|
||
|
||
## See Also
|
||
|
||
- [[Dankserver Stack]]
|
||
- [[ARR-Stack]] — automated download into Jellyfin libraries
|
||
- [[Copyparty]] — alternative file viewer for existing collections
|
||
- Plex — existing media server on this host
|