Minimum specs
| Part | Minimum | Recommended |
|---|---|---|
| CPU | Dual-core, 64-bit | Quad-core - Intel with Quick Sync is preferred |
| RAM | 2 GB | 4–8 GB (more if the same box runs an Arr stack) |
| Storage | ~2 GB for the app | Separate drive/array for media; SSD for the config + metadata folder |
| GPU | None needed for direct play | Intel Quick Sync, NVIDIA NVENC, or AMD VCN for hardware transcoding |
Step 1 — Install Jellyfin
Pick your platform
Docker Compose
Make a folder for the server (e.g. ~/jellyfin), save this as docker-compose.yml inside it, and edit /path/to/media to point at your library.
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000
network_mode: host # simplest for DLNA/discovery; or map ports below
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/media:/media
restart: unless-stopped
# devices:
# - /dev/dri:/dev/dri # Intel/AMD hardware transcodingIf you'd rather not use network_mode: host, drop that line and map ports instead:
ports:
- "8096:8096" # http
- "8920:8920" # https (optional)Then bring it up:
docker compose up -d
docker compose logs -f jellyfinPodman: the same file works with podman-compose up -d, or run it rootless with podman run using the same volume mounts.
Kubernetes: the image is the same — mount /config and /cache as PVCs, your media as a read-only PVC or NFS volume, and expose port 8096 via a Service. Skip network_mode: host; you lose DLNA auto-discovery but everything else works.
source: jellyfin.org — container install
Debian / Ubuntu
The official one-liner adds the Jellyfin repo and installs the server as a systemd service:
curl https://repo.jellyfin.org/install-debuntu.sh | sudo bashThen check it's running:
sudo systemctl status jellyfin
sudo systemctl enable --now jellyfinConfig lives in /etc/jellyfin, data and metadata in /var/lib/jellyfin. The service runs as the jellyfin user — that user needs read access to your media folders.
Open the port if ufw is on:
sudo ufw allow 8096/tcpFedora / RHEL / Arch: Jellyfin ships packages for those too — see the install docs below for the exact repo steps.
source: jellyfin.org — Linux install
Windows
- Download the Windows installer (
.exe) from the Jellyfin downloads page. - Run it. When asked, install as a service so the server starts with the machine instead of only when you're logged in.
- Allow it through Windows Firewall when prompted — otherwise nothing else on your network can reach it.
- It opens
http://localhost:8096when it's ready.
Running as a service means Jellyfin runs as LocalSystem, which cannot see mapped network drives. If your media is on a NAS, either use the full UNC path (\\NAS\media) with credentials, or set the service to log on as your user account.
Data lives in C:\ProgramData\Jellyfin\Server — that's the folder to back up.
source: jellyfin.org — Windows install
macOS
Easiest path is Homebrew:
brew install --cask jellyfin
brew services start jellyfinOr download the .dmg from the downloads page and drag it to Applications — it runs as a menu-bar app.
Data lives in ~/.local/share/jellyfin. Grant the app Full Disk Access in System Settings → Privacy & Security if your media sits in Movies, Downloads, or on an external drive.
VideoToolbox acceleration on macOS is limited and not officially supported the way Quick Sync/NVENC are on Linux and Windows. macOS is fine for a small library or direct-play-only setup — for a transcoding server, use Linux or Docker on other hardware.
source: jellyfin.org — macOS install
Step 2 — First-run setup wizard
Open http://SERVER_IP:8096 in a browser (use localhost if you're on the machine itself). The wizard runs once:
- Language — display language for the UI.
- Admin account — your username and password. This is the account that manages everything; make the password a real one, it's the only thing between the internet and your server if you ever expose it.
- Add media libraries — one library per content type. Pick the right Content type (Movies / Shows / Music), give it a display name, and point it at the folder. On Docker that's the path inside the container (
/media/movies), not the host path. - Metadata language & country — controls which artwork and titles get pulled.
- Remote access — leave "Allow remote connections" on for LAN use; leave automatic port mapping (UPnP) off. Don't port-forward Jellyfin to the open internet.
Jellyfin identifies media by filename. Movies as Movie Name (2024)/Movie Name (2024).mkv, shows as Show Name/Season 01/Show Name - S01E01.mkv. Get this right and metadata just appears; get it wrong and you'll be fixing matches by hand forever. An Arr stack handles this naming automatically.
After the wizard, go to Dashboard → Libraries and hit Scan All Libraries. First scan on a big library takes a while — it's downloading artwork and metadata for everything.
Step 3 — Turn on hardware transcoding
Go to Dashboard → Playback → Transcoding and set Hardware acceleration to match your hardware:
| Hardware | Pick this | Notes |
|---|---|---|
| Intel CPU with iGPU | Quick Sync (QSV) | Best value. 8th-gen and newer handles multiple 4K HEVC streams. Needs /dev/dri passed into the container. |
| NVIDIA GPU | NVENC | Strongest option. Consumer cards have a concurrent-encode limit; needs the NVIDIA Container Toolkit under Docker. |
| AMD GPU on Linux | VAAPI | Works well with the Mesa drivers. Also needs /dev/dri. |
| AMD GPU on Windows | AMF | Windows-only path for Radeon cards. |
| No GPU | None | CPU-only. Fine for direct play; expect one 1080p transcode at a time at best. |
Then tick the codecs your hardware can decode (H.264, HEVC, and VP9 on most modern chips), plus Enable hardware encoding. Leave Enable Tone mapping on if you have HDR content and clients that can't play it natively.
Docker: pass the GPU through
Intel/AMD — uncomment the devices block from Step 1:
devices:
- /dev/dri:/dev/driNVIDIA — install the NVIDIA Container Toolkit on the host, then add:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]Recreate the container after either change (docker compose up -d) — a restart isn't enough.
Linux: fix permissions
On a bare-metal Linux install the jellyfin user needs access to the GPU device:
sudo usermod -aG render,video jellyfin
sudo systemctl restart jellyfinVerify it's actually working
Play something that forces a transcode (change quality to a lower bitrate in the player), then open Dashboard → Activity. The stream should read Transcoding (hardware) — if it says Transcoding with no hardware note, the GPU isn't being used and it's falling back to CPU.
source: jellyfin.org — hardware acceleration
Step 4 — Jellyfin outside of the house
It is preferred that you do not port forward and use other options instead.
The low-effort, low-risk option is a mesh VPN — Tailscale, NetBird or WireGuard. Everyone installs a client, joins your network, and browses to the server's mesh IP. Works with CGNAT.
Another option is Zero Trust Network Access (ZTNA). This provides an inverse to a mesh VPN, not allowing any permissions to any services until given.
Ports reference
| Port | Protocol | What it's for |
|---|---|---|
8096 | TCP | Web UI / HTTP — the one you actually use |
8920 | TCP | HTTPS (optional, only if you configure a certificate) |
1900 | UDP | DLNA discovery (optional) |
7359 | UDP | Client auto-discovery on the LAN (optional) |
Quick reference
# Docker — bring it up
docker compose up -d
docker compose logs -f jellyfin
# Linux — install + enable
curl https://repo.jellyfin.org/install-debuntu.sh | sudo bash
sudo systemctl enable --now jellyfin
sudo ufw allow 8096/tcp
# Linux — GPU permissions for hardware transcoding
sudo usermod -aG render,video jellyfin
sudo systemctl restart jellyfin
# Config/data locations
# Docker ./config volume
# Linux /etc/jellyfin (config), /var/lib/jellyfin (data)
# Windows C:\ProgramData\Jellyfin\Server
# macOS ~/.local/share/jellyfin
# Web UI: http://SERVER_IP:8096Next: automate the library
Jellyfin is the media player, pair it with the Arr stack like Prowlarr, Sonarr, Radarr, and even Lidarr to help name, organize, and provide automatic library refreshes.