← Self-Hosting · Media · Replaces: Netflix-style streaming of your own films, Plex
What You'll Build
Jellyfin turns a folder of video files into a polished streaming service with posters, descriptions, "continue watching", and apps for smart TVs, phones, and browsers. It's completely free — no accounts, no premium tier, no tracking.
Port: 8096 · Time: 30 minutes · Difficulty: Easy (hardware transcoding is Medium)
Where the videos come from: rip DVDs and Blu-rays you own (MakeMKV + HandBrake), your own home videos, and DRM-free purchases. Downloading copyrighted films you don't own is illegal in most countries.
What You Need
- Your home server from Foundations 1 (Docker installed,
~/stacksfolder). - Nginx Proxy Manager with your
*.home.example.comcertificate (recommended). - Your videos on a drive, e.g.
/mnt/data/media.
Step 1: Organise the Files
Jellyfin looks up posters and details by folder and file name, so naming matters:
/mnt/data/media/
├── movies/
│ └── The Matrix (1999)/
│ └── The Matrix (1999).mkv
└── tv/
└── Planet Earth (2006)/
└── Season 01/
├── Planet Earth (2006) S01E01.mkv
└── Planet Earth (2006) S01E02.mkv
Step 2: Start Jellyfin
mkdir -p ~/stacks/jellyfin && cd ~/stacks/jellyfin
# Intel/AMD GPUs only: find the "render" group's number for hardware transcoding
getent group render | cut -d: -f3 # e.g. 993
nano compose.yaml
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: "1000:1000"
group_add:
- "993" # ← the render group number from above
ports:
- "8096:8096"
volumes:
- ./config:/config # settings, users, watch history
- ./cache:/cache # temporary transcoding files
- /mnt/data/media:/media:ro # your films and shows (read-only)
devices:
- /dev/dri:/dev/dri # Intel/AMD GPU for hardware transcoding (remove if none)
docker compose up -d
Step 3: The Setup Wizard
- Open
http://192.168.1.50:8096, choose your language, and create your admin user. - Add Media Library: type Movies, folder
/media/movies. Add another: type Shows, folder/media/tv. - Pick your metadata language and country → Next.
- Remote access: leave "Allow remote connections" on (it's needed for the proxy), but leave automatic port mapping off.
- Finish and log in. Posters appear as the library scan runs.
Step 4: Hardware Transcoding
When a device can't play a file directly (or you're on slow mobile data), Jellyfin converts it on the fly. A modern Intel iGPU does this easily; the CPU alone struggles with 4K.
- Dashboard → Playback → Transcoding.
- Hardware acceleration: Intel QuickSync (QSV) for Intel, or VAAPI for AMD. Device:
/dev/dri/renderD128. - Tick the codecs your GPU supports (H.264, HEVC; AV1 on very new chips) → Save.
- Test: play a film and pick a low quality from the settings (gear) menu. Dashboard → Activity should show "(HW)" for the stream.
Step 5: Watch on Every Screen
| Device | App |
|---|---|
| Android TV / Google TV / Fire TV | Jellyfin for Android TV |
| Roku, LG webOS, Samsung Tizen | Jellyfin (from the TV's app store; Samsung needs a manual install) |
| iPhone / iPad / Apple TV | Swiftfin, or Infuse (paid, excellent) |
| Android phone | Jellyfin, or Findroid |
| Computer | Web browser, or Jellyfin Media Player |
Server address in the apps: https://jellyfin.home.example.com. Create a separate user for each person so everyone has their own "continue watching" list; use parental ratings on kids' accounts.
Add It to Your Proxy, Dashboard, and Backups
- Nginx Proxy Manager: new proxy host
jellyfin.home.example.com→ schemehttp,192.168.1.50, port8096, Websockets on, your wildcard certificate, Force SSL. - Homepage: add a tile in
services.yaml(how). - Uptime Kuma: add an HTTP monitor for the new address (how).
- Backups:
~/stacks/jellyfinis already covered by the restic script. Your media folder is big and replaceable from the discs — back it up only if you have space.
Troubleshooting
- Film shows the wrong poster or none — check the folder/file naming, then on the item: ⋯ → Identify.
- Library is empty — the container can't read the folder. Check the
/mediapath and that user 1000 can read the files. - Playback buffers constantly — it's transcoding in software. Set up Step 4, or pick "Direct play" friendly formats (H.264/HEVC in MKV/MP4).
- "Permission denied" on /dev/dri — wrong render group number in
group_add.