Jellyfin is a free software media server — movies, shows, music, photos — with apps for basically every device and no premium tier, no code signing requirement, and no account. It transcodes on the fly so a 4K remux plays on a five-year-old phone.
What it is
Point it at a directory of files, it indexes them, groups them into libraries, and serves them to web, Android, iOS, Roku, Fire TV, and anything with a browser. Hardware transcoding is the difference between smooth playback and a buffering wheel, and it's supported for Intel QuickSync, NVIDIA and AMD.
Before you start
- Give the container
--device=/dev/drifor hardware transcoding. Without it, everything runs on the CPU and a 4K stream will stutter. - Use
READONLYon the media mount. Nothing should ever be able to write to your film library from a streaming client. - Don't try to transcode while seeding or if the host is doing other heavy work. Jellyfin will happily use every core and starve the rest of the server. Cap the transcode threads in the dashboard.
1 — Create the directories
mkdir -p ~/services/jellyfin/{config,cache,media}
# point "media" at your real library, e.g.
# ln -s /mnt/bigdisk/media ~/services/jellyfin/media/library
cd ~/services/jellyfin
2 — Write the compose file
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: "1000:1000"
devices:
- /dev/dri:/dev/dri
group_add:
- "${RENDER_GID:-104}"
ports:
- "127.0.0.1:8096:8096"
volumes:
- ./config:/config
- ./cache:/cache
- ./media:/media:ro
environment:
TZ: UTC
JELLYFIN_PublishedServerUrl: https://tv.example.com
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
interval: 60s
timeout: 10s
retries: 5
start_period: 60s
3 — Start it
docker compose up -d
docker compose logs -f jellyfin | grep -i "listening\|ffmpeg\|error"
4 — First-run setup
- Open
http://yourhost:8096and set the language and admin account. There's no default password, so the first account you make is the admin. - Add your media paths under Dashboard → Libraries. Use one folder per library so Jellyfin can infer the type —
/media/movies,/media/tv,/media/music. - Enable hardware acceleration in Dashboard → Playback → Transcoding. For an Intel iGPU choose QuickSync (VAAPI) with the
/dev/dri/renderD128device; for NVIDIA pick NVENC and pass the render device through. - Under Dashboard → Users, create a non-admin account for family members. Admin users can change server settings; you don't want that on the TV.
- Verify transcoding is actually being used: play a 4K file on a low-power client and watch for a "Transcoding" indicator, then check the dashboard's Active sessions.
5 — Keep it tidy
# run the library scan on a schedule instead of watching it churn
docker exec jellyfin curl -s http://localhost:8096/ScheduledTasks
# pre-optimize direct play profiles so phones don't transcode needlessly
# Settings → Playback → Transcoding → create an Android profile at 720p