← All articles
GETTING STARTED Building a Media Server with Jellyfin: The Complete ... 2026-02-09 · jellyfin · media · streaming

Building a Media Server with Jellyfin: The Complete Guide

Getting Started 2026-02-09 jellyfin media streaming plex

A media server is one of those home lab projects that the whole household actually benefits from. Instead of files scattered across hard drives and USB sticks, you get a Netflix-like interface for your entire media collection — movies, TV shows, music, photos — streamable to any device in the house. And unlike cloud streaming services, you own the content and the platform.

Jellyfin is the leading free, open-source media server. No accounts, no subscriptions, no telemetry, no artificial feature restrictions. It's a fully community-driven fork of Emby, and it's become the default recommendation in the self-hosting community for good reason.

This guide covers everything from installation to hardware transcoding, client apps, remote access, and honest comparisons with the alternatives.

Why Jellyfin Over Plex or Emby?

Before we set anything up, let's talk about the landscape. There are three major media server platforms, and they each have distinct trade-offs.

Jellyfin

Plex

Emby

The bottom line: If you value open source and privacy, Jellyfin is the clear choice. If you need the best possible client experience on every device (especially smart TVs and game consoles), Plex is hard to beat. If you're undecided, start with Jellyfin — it's free, and you can always switch later.

Installation

Docker (Recommended)

Docker is the cleanest way to run Jellyfin. One container, easy updates, no dependency conflicts.

# docker-compose.yml
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "8096:8096"     # Web UI (HTTP)
      - "8920:8920"     # Web UI (HTTPS, optional)
      - "7359:7359/udp" # Client discovery on local network
      - "1900:1900/udp" # DLNA (optional)
    environment:
      - JELLYFIN_PublishedServerUrl=http://192.168.1.50
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media/movies:/data/movies
      - /mnt/media/shows:/data/shows
      - /mnt/media/music:/data/music
    devices:
      - /dev/dri:/dev/dri  # Intel GPU for hardware transcoding
docker compose up -d

Open http://192.168.1.50:8096 in your browser. The setup wizard walks you through creating an admin account, selecting your language, and adding your first library.

Bare Metal (Debian/Ubuntu)

If you prefer running Jellyfin directly on the OS:

# Add the Jellyfin repository
sudo apt install curl gnupg
curl -fsSL https://repo.jellyfin.org/install-debuntu.sh | sudo bash

# Install Jellyfin
sudo apt install jellyfin

# Start and enable
sudo systemctl enable --now jellyfin

# Check status
sudo systemctl status jellyfin

Jellyfin runs on port 8096 by default. The service runs as the jellyfin user, so make sure your media directories are readable by that user.

LXC Container (Proxmox)

If you're running Proxmox, an unprivileged LXC container works well for Jellyfin. Create an Ubuntu 24.04 container, then follow the bare metal steps above. For hardware transcoding in LXC, you'll need to pass through the GPU device — see the transcoding section below.

Organizing Your Media Library

Jellyfin (and its metadata scrapers) expects a specific directory structure. Get this right from the start and you'll avoid 90% of metadata issues.

Movies

/data/movies/
├── Blade Runner 2049 (2017)/
│   └── Blade Runner 2049 (2017).mkv
├── The Matrix (1999)/
│   ├── The Matrix (1999).mkv
│   └── The Matrix (1999).srt          # External subtitles
├── Dune Part Two (2024)/
│   └── Dune.Part.Two.2024.2160p.mkv
└── My Neighbor Totoro (1988)/
    └── My Neighbor Totoro (1988).mkv

The key rules:

TV Shows

/data/shows/
├── Breaking Bad/
│   ├── Season 01/
│   │   ├── Breaking Bad S01E01.mkv
│   │   ├── Breaking Bad S01E02.mkv
│   │   └── ...
│   ├── Season 02/
│   │   ├── Breaking Bad S02E01.mkv
│   │   └── ...
│   └── Season 05/
│       └── ...
├── Severance/
│   ├── Season 01/
│   │   ├── Severance S01E01.mkv
│   │   └── ...
│   └── Season 02/
│       └── ...
└── Shogun (2024)/
    └── Season 01/
        └── ...

The S01E01 naming convention is essential. Jellyfin uses it to match episodes to metadata. Absolute episode numbering (E001, E002) works for anime.

Music

/data/music/
├── Pink Floyd/
│   ├── The Dark Side of the Moon (1973)/
│   │   ├── 01 - Speak to Me.flac
│   │   ├── 02 - Breathe.flac
│   │   └── ...
│   └── Wish You Were Here (1975)/
│       └── ...
└── Radiohead/
    └── OK Computer (1997)/
        └── ...

For music, proper ID3/Vorbis tags matter more than file names. Jellyfin reads embedded tags for artist, album, and track metadata.

Adding Libraries

In the Jellyfin dashboard:

  1. Go to Dashboard > Libraries
  2. Click Add Media Library
  3. Choose the content type (Movies, Shows, Music, etc.)
  4. Select the folder path (/data/movies, /data/shows, etc.)
  5. Choose your metadata providers:
    • Movies: TheMovieDb is the default and works well
    • TV Shows: TheMovieDb or TheTVDB
    • Music: MusicBrainz

Jellyfin scans the library and downloads metadata, artwork, and descriptions automatically. The initial scan can take a while for large libraries — let it run in the background.

Metadata Tips

Hardware Transcoding

Transcoding is the process of converting video from one format to another on the fly. When a client can't play the original format (wrong codec, resolution too high, or bandwidth too low), Jellyfin transcodes it in real time.

Software transcoding (CPU-only) works but hammers your processor. A 4K HEVC to 1080p H.264 transcode can peg an 8-core CPU at 100%. Hardware transcoding offloads this to a GPU, dropping CPU usage to near zero.

Intel Quick Sync (QSV)

Intel's integrated GPUs (6th gen Skylake and newer) include Quick Sync Video, which is excellent for transcoding. This is the most popular choice in home labs because most Intel CPUs have it built in — no discrete GPU needed.

# Docker Compose — pass through the Intel GPU
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    devices:
      - /dev/dri:/dev/dri
    group_add:
      - "105"  # render group GID — check with: getent group render
# Verify Intel GPU is available on the host
ls /dev/dri/
# Should show: card0  renderD128

# Check the render group GID
getent group render
# render:x:105:

In Jellyfin settings:

  1. Go to Dashboard > Playback > Transcoding
  2. Set Hardware Acceleration to Intel QuickSync (QSV)
  3. Enable the codecs your GPU supports (H.264, HEVC, VP9, AV1 depending on generation)
  4. Enable Hardware Decoding and Hardware Encoding
  5. Enable Tone Mapping for HDR to SDR conversion if you have 10th gen or newer

Quick Sync generation capabilities:

Intel Gen H.264 HEVC VP9 AV1 HDR Tone Mapping
6th (Skylake) Decode + Encode Decode only No No No
7th-9th Decode + Encode Decode + Encode Decode only No No
10th-11th Decode + Encode Decode + Encode Decode + Encode No Yes
12th+ Decode + Encode Decode + Encode Decode + Encode Decode + Encode Yes

The Intel N100 (common in mini PCs like the Beelink EQ12) is a 12th-gen chip with full AV1 support and HDR tone mapping, all at 6W idle. It's arguably the best transcoding CPU per watt for a home lab.

NVIDIA NVENC

If you have a discrete NVIDIA GPU (GTX 1050 or newer), NVENC is powerful and well-supported:

# Docker Compose — NVIDIA GPU passthrough
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
# Install NVIDIA Container Toolkit first
# See: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html

# Verify GPU is accessible in container
docker exec jellyfin nvidia-smi

In Jellyfin settings, set Hardware Acceleration to NVIDIA NVENC.

NVIDIA GPUs are overkill for most home labs but useful if you already have one from a gaming PC. They handle more simultaneous transcodes than Intel QSV.

AMD AMF / VA-API

AMD GPUs and APUs support VA-API for transcoding. Support in Jellyfin is functional but less mature than Intel QSV or NVIDIA NVENC. Pass through /dev/dri the same way as Intel, and select Video Acceleration API (VA-API) in Jellyfin settings.

Avoiding Transcoding Entirely

The best transcode is no transcode. If all your clients can direct-play your media, you don't need transcoding at all. To maximize direct play:

Most modern clients (Android TV, Apple TV, Fire Stick 4K, web browser) handle H.264 1080p in an MKV container without transcoding. HEVC/H.265 and 4K are where transcoding becomes necessary for older or less capable clients.

Client Apps

Jellyfin has clients for most platforms. Quality varies:

Excellent

Good

Other Options

The Client App Gap with Plex

This is where Plex genuinely wins. Plex has native apps on virtually every platform — smart TVs, game consoles (PlayStation, Xbox), and they're all polished. If your primary consumption device is a Samsung TV or a PlayStation, Plex is the path of least resistance. Jellyfin's strategy relies more on Android TV devices and streaming sticks, which is a reasonable workaround.

Remote Access

Accessing your media server outside your home requires exposing Jellyfin to the internet. There are several approaches, ordered from most to least secure:

Tailscale / WireGuard VPN (Recommended)

The safest option. Set up a VPN and your remote devices access Jellyfin as if they were on your home network. No ports exposed to the internet.

# Install Tailscale on your Jellyfin server
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

# Your Jellyfin server gets a Tailscale IP (e.g., 100.x.y.z)
# Access Jellyfin from anywhere: http://100.x.y.z:8096

The downside: every client device needs Tailscale or WireGuard installed. This works great for your own phone and laptop, but it's a pain for family members' devices.

Reverse Proxy with SSL

Expose Jellyfin through a reverse proxy (Traefik, Nginx, Caddy) with HTTPS. This requires a domain name and port forwarding on your router.

# Nginx reverse proxy config
server {
    listen 443 ssl;
    server_name jellyfin.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/jellyfin.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/jellyfin.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://192.168.1.50:8096;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support (required for Jellyfin)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Cloudflare Tunnel

Cloudflare Tunnels expose your Jellyfin instance without opening any ports on your router. Traffic routes through Cloudflare's network.

# Install cloudflared and authenticate
cloudflared tunnel create jellyfin
cloudflared tunnel route dns jellyfin jellyfin.yourdomain.com

# Configure the tunnel
# ~/.cloudflared/config.yml
tunnel: <tunnel-id>
credentials-file: /path/to/credentials.json

ingress:
  - hostname: jellyfin.yourdomain.com
    service: http://localhost:8096
  - service: http_status:404

Note: Cloudflare's terms of service technically prohibit using their free tier for streaming large video files. Many people do it anyway for personal use, but be aware of the limitation.

Useful Plugins

Jellyfin's plugin system extends its capabilities. Install them from Dashboard > Plugins > Catalog.

Maintenance and Performance

Regular Tasks

# Update Jellyfin (Docker)
docker compose pull && docker compose up -d

# Check Jellyfin logs
docker logs jellyfin --tail 100 -f

# Clean up transcoding cache (can grow large)
# Jellyfin usually handles this, but if your cache drive fills up:
rm -rf ./cache/transcodes/*

Performance Tuning

User Management

Jellyfin supports multiple user accounts with per-user library access and parental controls:

  1. Go to Dashboard > Users
  2. Create accounts for family members
  3. Set per-user permissions: which libraries they can see, whether they can download, maximum streaming bitrate, parental rating limits
  4. Each user gets their own watch history and "Continue Watching" queue

Migration from Plex

If you're coming from Plex, here's what to expect:

Jellyfin is the media server that respects your ownership. No accounts to create, no subscriptions to manage, no company deciding which features you get. Your media, your server, your rules. For a home lab, that philosophy fits perfectly.