Install via Docker / Podman
# docker-compose.yml
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: 1000:1000 # match your media files' ownership
ports:
- "8096:8096" # HTTP
- "8920:8920" # HTTPS (optional, usually proxied)
- "7359:7359/udp" # Client discovery (LAN)
- "1900:1900/udp" # DLNA
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/media/movies:/media/movies:ro
- /mnt/media/tv:/media/tv:ro
- /mnt/media/music:/media/music:ro
# Hardware acceleration via /dev/dri (Intel iGPU / AMD)
devices:
- /dev/dri:/dev/dri
# Or NVIDIA — uncomment if applicable
# deploy:
# resources:
# reservations:
# devices:
# - capabilities: [gpu]
# runtime: nvidia
Mounting media read-only (:ro) is good hygiene — Jellyfin doesn't write to the media itself, only to its cache + metadata in /config.
First-run setup
Browse to http://<host>:8096/:
- Pick language.
- Create an admin user. Strong password — Jellyfin won't enforce it.
- Add libraries:
- Type: Movies → Folder:
/media/movies→ Metadata: prefer TheMovieDb - Type: Shows → Folder:
/media/tv→ Metadata: prefer TheMovieDb / TheTVDB - Type: Music → Folder:
/media/music→ Metadata: MusicBrainz
- Type: Movies → Folder:
- Remote access: disable for now (default port 8096 over plain HTTP isn't safe to expose); set up the reverse proxy below.
First library scan takes a while — Jellyfin fetches posters, cast info, plot summaries from external metadata providers.
Media library file naming
Jellyfin scrapes metadata by parsing the filename. The conventions:
# Movies: one folder per movie, optional year disambiguates
/media/movies/
The Matrix (1999)/
The Matrix (1999).mkv
The Matrix (1999).en.srt
Dune Part Two (2024)/
Dune Part Two (2024).mkv
# TV shows: Show / Season / Episode with SxxExx
/media/tv/
Severance/
Season 01/
Severance - S01E01 - Good News About Hell.mkv
Severance - S01E02 - Half Loop.mkv
# Music: Artist / Album / Track
/media/music/
Radiohead/
OK Computer (1997)/
01 - Airbag.flac
02 - Paranoid Android.flac
Off-spec names mostly still get matched, but the canonical layout makes mismatches rare.
Reverse proxy with HTTPS
# Caddy
media.example.com {
reverse_proxy 127.0.0.1:8096
# Jellyfin uses WebSockets for live state
@ws {
path /socket
header Connection *Upgrade*
header Upgrade websocket
}
handle @ws {
reverse_proxy 127.0.0.1:8096
}
}
In Jellyfin: Dashboard → Networking → "Published Server URLs" → add https://media.example.com. This affects how mobile/TV clients construct download URLs.
Hardware-accelerated transcoding
Transcoding (re-encoding a 4K HEVC source on the fly to 1080p H.264 for a phone that can't direct-play it) is CPU-expensive. Hardware acceleration delegates this to the GPU's video encoder/decoder block:
- Intel iGPU — cheapest hardware option; QuickSync handles H.264, H.265, AV1 (gen 11+). Mount
/dev/dri; Dashboard → Playback → Hardware acceleration: VA-API or Intel QSV. - AMD GPU — VA-API. Same
/dev/dri. - NVIDIA — NVENC. Needs the NVIDIA Container Toolkit and a Jellyfin image variant with NVIDIA drivers.
- Apple Silicon — VideoToolbox. Mac-only.
To verify transcoding is actually using hardware: play a file that requires transcoding, then check Dashboard → Sessions — the session should show "Transcoding (Hardware)."
Per-user permissions
Dashboard → Users → Add. Per user:
- Which libraries they can see
- Whether they can download content (vs stream-only)
- Max streaming bitrate (over LAN / over internet)
- Parental rating limits
- Whether they can remote-access
Mobile and TV clients
- Jellyfin Mobile on iOS / Android — official.
- Findroid / Streamyfin — third-party Android clients, often nicer UI.
- Swiftfin — native iOS / tvOS client; the best Apple TV experience.
- Jellyfin for Android TV — official, mostly stable.
- Kodi + Jellyfin add-on — for hardcore Kodi users who want Jellyfin as the library backend.
- Roku — via the Jellyfin Roku channel.
- LG webOS, Samsung Tizen — community-maintained apps, install instructions on the wiki.
Plugins worth knowing
- Skip Intro / Outro detector — analyzes audio to detect repeated intros across episodes, surfaces a "Skip Intro" button.
- Trakt — sync watch state to Trakt.tv for social features.
- Reports — library stats: how much watched, biggest files, most-watched users.
- Webhook — trigger notifications on playback events.
Companion ecosystem
- Sonarr — automatically download and rename new TV episodes.
- Radarr — same for movies.
- Bazarr — subtitle automation.
- Prowlarr — indexer aggregator that feeds Sonarr/Radarr.
- Jellyseerr — request management for media (users request titles; admin approves; Sonarr/Radarr fetches).
This whole stack ("the *arr stack") is the canonical pairing for serious self-hosted media; Jellyfin is the front-end.
Backups
The ./config directory is everything that matters — users, libraries, watch state, metadata, configuration. A nightly restic job (see that tutorial) on it is sufficient. The media itself is on disk separately; back that up only if losing it would matter (rip again from physical originals if applicable).