How to Install Jellyfin on a Linux Server (Your Own Netflix, No Subscription)

Jellyfin turns a folder of films, TV episodes and music into a streaming service with posters, descriptions, resume-where-you-left-off and apps for every TV, phone and browser. It's free and entirely yours — no account with anyone, no tracking, no "this title is leaving next month".
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/jellyfin/compose.yaml |
| Media | /mnt/data/media/Movies, /mnt/data/media/TV, /mnt/data/media/Music |
| First visit | http://server-ip:8096 |
| Apps | Jellyfin on Android TV, Fire TV, iOS, Android, LG, Samsung; or any browser |
| Rescan library | Dashboard → Libraries → Scan |
1. Organise the media first
Jellyfin recognises things by file and folder name. Follow this and it finds the posters and descriptions by itself:
media/
Movies/
The Matrix (1999)/The Matrix (1999).mkv
TV/
Doctor Who (2005)/Season 01/Doctor Who S01E01.mkv
Music/
Artist/Album/01 - Track.flac
Film: Title (Year). TV: show folder, season folder, S01E01 in the filename. That's all it needs.
2. The compose file
mkdir -p ~/docker/jellyfin && cd ~/docker/jellyfin
nano compose.yaml
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000
ports:
- "8096:8096"
environment:
TZ: Europe/London
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/data/media:/media:ro
devices:
- /dev/dri:/dev/dri
restart: unless-stopped
- user: 1000:1000 runs it as your user (check with id) so it can read your files.
- /media:ro — read-only. Jellyfin never needs to change your files.
- devices: /dev/dri gives it the Intel or AMD GPU for hardware transcoding. Remove the block on a machine without one, or on a Raspberry Pi.
docker compose up -d
sudo ufw allow 8096/tcp
3. First run
Open http://192.168.1.50:8096. Choose a language, create the admin user, then Add media library: content type Movies, folder /media/Movies. Repeat for TV and Music. Leave metadata downloaders on. Finish, and it starts scanning — a big library takes a while.
4. Hardware transcoding
Most of the time Jellyfin streams the file as-is. When a device can't play the format, Jellyfin converts it live, which is heavy on the CPU. Let the GPU do it instead: Dashboard → Playback → Transcoding → Hardware acceleration: VAAPI (Intel/AMD) and tick the formats listed. On the server, make sure your user can use the GPU: sudo usermod -aG render,video $USER, and add the same group IDs under group_add: in the compose file if playback fails.
5. Apps
Install Jellyfin on the TV (Android TV, Fire TV, LG, Samsung, Roku all have it), enter the server address, log in. Phones the same. In a browser, the address is enough. Away from home, use the VPN or a reverse proxy with HTTPS — don't expose 8096 directly.
Useful extras
- Users: Dashboard → Users. Give the kids an account with a parental rating limit.
- Subtitles: the Open Subtitles plugin fetches them automatically.
- Music on the go: Finamp (iOS/Android) is a dedicated Jellyfin music app.
- Requests and automation: Jellyseerr, Sonarr and Radarr sit alongside Jellyfin in the same compose folder if you want the full setup.
Troubleshooting
Library is empty after scanning. Permissions — the container's user can't read the files. ls -l /mnt/data/media and chmod -R a+rX /mnt/data/media.
Wrong film matched. Right-click → Identify, and search by title and year. Renaming the folder correctly stops it recurring.
Buffering on the TV. It's transcoding on the CPU. Enable hardware acceleration, or pick a direct-play format when ripping (H.264 in an MKV plays on almost everything).
Playback fails only through Nginx. Add proxy_buffering off; and the WebSocket lines to the server block.
Wrapping up
Name the files properly, one compose file with the media folder read-only, add a library, install the TV app. Half an hour and the DVD shelf is a streaming service you own outright.
