Quick answer

Jellyfin’s setup hinges on the host first: /dev/dri/renderD128 for Intel Quick Sync or AMD VAAPI, or the NVIDIA Container Toolkit for NVENC. With that present, it is one linuxserver container on 8096, with PUID/PGID 1000, media bind mounts, and Nginx Proxy Manager with Websockets on. Choose media paths before starting; changing them means re-adding libraries.

By LK Wood IV · 2026-05-25 · ~12 min read · St. Louis County, MO

Architecture diagram of a Jellyfin Docker homelab: movies, TV and music volume mounts plus an SSD transcode cache feed the linuxserver Jellyfin container on port 8096, with three hardware transcoding paths (Intel Quick Sync via /dev/dri, NVIDIA NVENC via the nvidia runtime, AMD VAAPI via renderD128), fronted by Nginx Proxy Manager HTTPS and Tailscale remote access to Apple TV, Roku, iOS and web clients

Jellyfin is a free, open-source media server. No subscription, no required cloud account, no phoning home. It runs on your own hardware, serves your own files, and the transcoding works whether you pay anyone money or not.

This guide sets up Jellyfin in Docker with hardware transcoding for Intel, NVIDIA, and AMD GPUs, HTTPS via Nginx Proxy Manager, and Tailscale remote access.

(Still choosing? Jellyfin vs Emby compares it against the project it was forked from, and Jellyfin vs Plex covers the other common alternative. Come back here to build it.)

What you’ll have at the end

  • Jellyfin running in Docker on your homelab host
  • Hardware transcoding configured (Intel QSV, NVIDIA, or AMD VAAPI)
  • HTTPS access at jellyfin.yourdomain.com via Nginx Proxy Manager
  • Remote access via Tailscale without opening ports
  • Metadata scraping from TMDB and TheTVDB

Prerequisites

  • Docker installed on a Linux host (Proxmox LXC, VM, or bare-metal Debian/Ubuntu)
  • For NVIDIA transcoding: NVIDIA Container Toolkit installed
  • For Intel QSV: Intel 6th gen+ CPU (built-in GPU with Quick Sync)
  • Nginx Proxy Manager running for HTTPS (or skip and use LAN IP)

Step 1: Prepare media directories

Decide where your media lives before starting the container. The paths you choose here become the volume mounts in Docker Compose and can’t be easily changed later without restarting and re-adding libraries in the UI.

# Example structure on a NAS mount or local disk
mkdir -p /mnt/media/{movies,tv,music,photos}

# Or on local storage
mkdir -p /opt/media/{movies,tv}

Set ownership if running Jellyfin as non-root:

# Jellyfin container runs as UID/GID 1000 by default with linuxserver image
chown -R 1000:1000 /mnt/media

Step 2: Docker Compose

mkdir -p /opt/stacks/jellyfin && cd /opt/stacks/jellyfin

Base compose file (CPU transcoding or Intel QSV):

# /opt/stacks/jellyfin/docker-compose.yml
services:
  jellyfin:
    image: lscr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
      - JELLYFIN_PublishedServerUrl=https://jellyfin.yourdomain.com  # optional
    volumes:
      - ./config:/config
      - /mnt/media/movies:/data/movies
      - /mnt/media/tv:/data/tv
      - /mnt/media/music:/data/music
      - /tmp/jellyfin-transcode:/transcode   # SSD path for transcode cache
    ports:
      - 8096:8096    # HTTP
      - 8920:8920    # HTTPS (optional, if not using NPM)
    networks:
      - proxy
    # Intel QSV — add this if you have an Intel CPU with Quick Sync:
    # devices:
    #   - /dev/dri:/dev/dri
    # group_add:
    #   - "video"
    #   - "render"

networks:
  proxy:
    external: true

For Intel Quick Sync (QSV/VAAPI) — uncomment the device section above:

    devices:
      - /dev/dri:/dev/dri
    group_add:
      - "video"
      - "render"

Verify the /dev/dri device exists on the host:

ls /dev/dri
# renderD128  card0   (you should see renderD128 at minimum)

For NVIDIA GPU transcoding — use this compose instead:

services:
  jellyfin:
    image: lscr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - ./config:/config
      - /mnt/media/movies:/data/movies
      - /mnt/media/tv:/data/tv
      - /tmp/jellyfin-transcode:/transcode
    ports:
      - 8096:8096
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    networks:
      - proxy

networks:
  proxy:
    external: true

The NVIDIA Container Toolkit must be installed on the host. See the GPU transcoding guide for the toolkit install commands.

Start Jellyfin:

docker compose up -d
docker compose logs -f jellyfin

First startup takes 60–90 seconds as Jellyfin initializes its database. Access at http://your-host-ip:8096.

Step 3: Initial setup wizard

The wizard walks you through:

  1. Language — pick your locale
  2. Create admin account — use a strong password
  3. Add media libraries — this is where your /data/movies, /data/tv mounts are used:
    • Add library → Content type: Movies → Add folder → /data/movies
    • Add library → Content type: Shows → Add folder → /data/tv
  4. Preferred metadata language — English (or your locale)
  5. Enable remote access — leave on for now, configure access control after

After the wizard, Jellyfin starts scraping metadata from TMDB/TheTVDB immediately. For a large library, this takes 10–30 minutes.

Step 4: Enable hardware transcoding

In Jellyfin → Dashboard → Playback → Transcoding:

Intel Quick Sync (most Intel CPUs 6th gen+):

  • Hardware acceleration: Intel QuickSync (QSV)
  • Enable hardware encoding: on
  • H.264, HEVC, VP9, AV1 encode/decode: enable all that your CPU supports

NVIDIA GPU:

  • Hardware acceleration: Nvidia NVENC
  • Enable hardware encoding: on
  • H.264, HEVC, AV1 encode/decode: enable based on your GPU generation (RTX 4000+ supports AV1)

AMD (VAAPI):

  • Hardware acceleration: Video Acceleration API (VAAPI)
  • VA API device: /dev/dri/renderD128
  • Enable hardware encoding: on

Verify transcoding is working:

Play a video and intentionally trigger a transcode by selecting a lower quality than the source (e.g., source is 4K HEVC, select “1080p 8Mbps” in the quality settings). Watch the Jellyfin dashboard → Active Sessions — you should see the stream marked as HEVC → H264 (hw) or similar, with GPU utilization on the host.

On a mini PC with Intel N-series, a single 4K → 1080p HEVC transcode should consume under 15% CPU with Quick Sync active (vs 80–100% without it).

Step 5: Nginx Proxy Manager HTTPS

In NPM → Add Proxy Host:

  • Domain: jellyfin.yourdomain.com
  • Scheme: http
  • Forward hostname: jellyfin (container name, on proxy network)
  • Port: 8096
  • Websockets Support: ON (required for Jellyfin’s sync features)
  • SSL: wildcard cert, Force SSL on, HTTP/2 support on

Access Jellyfin at https://jellyfin.yourdomain.com.

Optional — allow direct access for LAN clients:

Some Jellyfin clients (especially smart TV apps) work better with a direct LAN IP if the DNS resolves. Add 192.168.1.X to the Jellyfin “Known Proxies and Networks” list in Dashboard → Networking so Jellyfin knows to trust the X-Forwarded-For header from NPM.

Step 6: Remote access via Tailscale

The simplest secure remote access is Tailscale:

  1. Install Tailscale on your homelab host (or in a Proxmox LXC)
  2. Enable subnet routing to advertise your homelab LAN: tailscale up --advertise-routes=192.168.1.0/24
  3. On each device (phone, laptop, etc.) that you want Jellyfin access from, install the Tailscale app and connect
  4. Access Jellyfin via the local LAN IP or via the NPM domain if you’ve set AdGuard Home DNS rewrites

The Jellyfin iOS/Android apps work identically over Tailscale as they do on your local network. No special configuration needed in Jellyfin itself.

Step 7: Jellyfin app clients

PlatformAppNotes
AndroidJellyfin (official)Play Store
iOS / iPadOSJellyfin (official)App Store
Apple TVJellyfin (official)tvOS App Store
Android TV / Fire TVJellyfin (official)Available on both stores
RokuJellyfin for RokuChannel Store
Web browserBuilt-in web clientAt your Jellyfin URL
Desktop (Windows/macOS/Linux)Jellyfin Media PlayerGitHub releases
KodiJellyfin for KodiKodi repository

On Apple TV and Android TV, the Jellyfin app supports Direct Play for most common formats (H.264/HEVC MP4/MKV containers). If the container or audio codec requires a transcode, hardware transcoding on the server handles it.

Library organization best practices

Name your files correctly. Jellyfin uses the TMDB naming convention:

/data/movies/The Dark Knight (2008)/The Dark Knight (2008).mkv
/data/tv/Breaking Bad/Season 01/Breaking Bad S01E01.mkv

The year in the movie folder name is required for disambiguation. TV shows need Season folders with SxxExx naming. Wrong naming is the #1 reason metadata fails to scrape.

Extras and specials:

/data/movies/The Dark Knight (2008)/
  The Dark Knight (2008).mkv
  extras/
    The Dark Knight Behind the Scenes.mkv

Jellyfin picks up extras from an extras/ subdirectory and shows them in the detail view.

Subtitles:

External subtitle files go in the same directory as the video with matching name:

The Dark Knight (2008).mkv
The Dark Knight (2008).en.srt        # English SRT
The Dark Knight (2008).en.forced.srt  # Forced English subtitles

Jellyfin surfaces these in the subtitle selection in the player.

Performance reference

Hardware transcoding throughput measured on Intel N100 (Quick Sync, 4K HEVC → 1080p H.264):

Concurrent streamsCPU loadTranscode FPS
1~8%60–90 fps
2~14%55–80 fps each
3~20%45–70 fps each
4~28%40–60 fps each

At 4 concurrent 4K → 1080p transcodes, playback remains smooth on a $160 N100 mini PC. Software transcoding (CPU only) would saturate all 4 N100 cores on a single 4K stream.

For the full GPU hardware comparison across Intel QSV, NVIDIA, and AMD, see the Best GPU for Jellyfin Transcoding guide.


For the Arr stack (Radarr, Sonarr, Prowlarr) that populates your Jellyfin library automatically, the Docker Compose starter stack covers the service stack with shared proxy networking. For transcoding GPU picks and benchmarks across platforms, see the GPU transcoding comparison. If you’re deciding between Jellyfin and Plex, the Jellyfin vs Plex comparison breaks down hardware transcoding cost, privacy, remote access, and app quality by use case. If your library also includes audiobooks, the AudioBookshelf Docker setup covers the purpose-built server for them, with per-user progress sync across mobile apps.

Sources

Frequently asked questions

Does Jellyfin need a GPU for transcoding?
No, but it helps. Jellyfin can software-transcode on CPU using ffmpeg. On a modern mini PC (N100/N150), software transcoding handles 1080p to 720p at 1080p → 720p at reasonable quality. The problem is 4K → 1080p: software transcoding an H.265 4K stream demands 6–10 CPU cores and typically fails to deliver smooth playback. Intel Quick Sync (built into almost every Intel CPU since 8th gen) handles 4K H.265 hardware transcoding at under 10% CPU with no additional hardware. For multiple simultaneous streams, hardware transcoding is the difference between a working media server and one that falls over.
Is Jellyfin actually better than Plex in 2026?
For homelab use, yes. Jellyfin requires no subscription for hardware transcoding, no account requirement for remote access, and no calls to Plex’s cloud infrastructure for playback. The apps on Apple TV, Roku, Android TV, Fire TV, iOS, and Android have reached practical parity with Plex’s basics. Plex still wins on polish in the mobile app and on ease of setup for non-technical family members. If you’re managing the server yourself and value control and no cloud dependency, Jellyfin is the better choice.
Can I run Jellyfin and the Arr stack (Radarr, Sonarr) together?
Yes. Jellyfin integrates with the Arr apps through shared volume mounts — the Arr stack downloads to /media/movies and /media/tv, and Jellyfin watches those same directories. No special integration plugin is needed; they communicate through the filesystem. The Docker Compose starter stack covers the networking between them.
How much storage does Jellyfin itself use?
Jellyfin’s application data (metadata, thumbnails, trickplay images, transcoding temp files) lives in its config directory. A library with 500 movies and 20 TV series will generate 5–15GB of metadata and thumbnails. The main storage concern is your media — Jellyfin itself is lightweight. Transcode cache is ephemeral and should be pointed at a fast (SSD) path rather than your NAS share.
How do I access Jellyfin outside my home network?
Two main options: Tailscale (zero-config VPN, your devices connect to your homelab LAN as if they’re on it locally) or exposing Jellyfin directly via Nginx Proxy Manager with a valid SSL cert. Tailscale is simpler and more secure — no ports open to the internet. Direct HTTPS works but requires a public domain and makes Jellyfin reachable to anyone who finds the URL. For family members on your Tailscale network, the direct Jellyfin URL works seamlessly. For sharing with people outside your Tailscale network, HTTPS is necessary.

Evidence ledger

Last updated
Methodology
This tutorial was written and edited by Lowell K. Wood IV in St. Louis County, MO. Specs, prices, commands, and version numbers are drawn from the official vendor, reseller, and project documentation current on the date above, and were verified before publishing. First-person hardware claims appear only where the article shows a verifiable artifact — a photo, receipt, or measurement — or links to the TechFuelHQ Open Bench Datasets. Every fact is human-verified against its cited source before publishing; AI assists with first-draft structure and source-gathering, not with the verdict. Full editorial standard: methodology.
Update log
  • 2026-07-25 — Last reviewed and updated.
Corrections
Spotted an error or stale price? Email hello@techfuelhq.com. Confirmed corrections are added to the update log above.

About the author

Written by Lowell K. Wood IV. Lowell builds and runs TechFuelHQ from St. Louis, Missouri, pairing thirteen-plus years of hands-on homelab, PC, server, and networking experience with cited third-party testing and first-party benchmarks on the gear he still runs. He also works ground EMS as a Nationally Registered Paramedic (NREMT).