Set Up Jellyfin

sources:Jellyfin Install DocsHardware Acceleration

Minimum specs

PartMinimumRecommended
CPUDual-core, 64-bitQuad-core - Intel with Quick Sync is preferred
RAM2 GB4–8 GB (more if the same box runs an Arr stack)
Storage~2 GB for the appSeparate drive/array for media; SSD for the config + metadata folder
GPUNone needed for direct playIntel 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 transcoding

If 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 jellyfin

Podman: 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

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:

  1. Language — display language for the UI.
  2. 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.
  3. 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.
  4. Metadata language & country — controls which artwork and titles get pulled.
  5. 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.
Naming matters more than you think

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:

HardwarePick thisNotes
Intel CPU with iGPUQuick Sync (QSV)Best value. 8th-gen and newer handles multiple 4K HEVC streams. Needs /dev/dri passed into the container.
NVIDIA GPUNVENCStrongest option. Consumer cards have a concurrent-encode limit; needs the NVIDIA Container Toolkit under Docker.
AMD GPU on LinuxVAAPIWorks well with the Mesa drivers. Also needs /dev/dri.
AMD GPU on WindowsAMFWindows-only path for Radeon cards.
No GPUNoneCPU-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/dri

NVIDIA — 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 jellyfin

Verify 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

PortProtocolWhat it's for
8096TCPWeb UI / HTTP — the one you actually use
8920TCPHTTPS (optional, only if you configure a certificate)
1900UDPDLNA discovery (optional)
7359UDPClient 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:8096

Next: 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.

→ Set up the Arr stack (Prowlarr, Sonarr, Radarr, Lidarr)