How to Set Up Jellyfin on Docker: A Complete Beginner's Guide to Self-Hosted Media Streaming
Step-by-step guide to setting up Jellyfin on Docker for self-hosted media streaming. Covers installation, hardware transcoding, remote access, and common mistakes.
Author
David Okonkwo
**FTC Disclosure:** This article contains affiliate links. If you purchase through these links, we may earn a commission at no additional cost to you. We only recommend products we have personally tested or thoroughly researched.
How to Set Up Jellyfin on Docker: A Complete Beginner's Guide to Self-Hosted Media Streaming
Key Takeaways
If you've been thinking about cutting ties with paid streaming services or finally setting up a media server for your DVD collection, you've probably heard about Jellyfin. And if you're like most homelabbers I talk to, you might have searched for a setup guide only to find instructions that assume you already know Docker, networking, and hardware transcoding inside out.
Here is the truth: setting up Jellyfin on Docker is one of the most rewarding self-hosting projects you can start with. Once it is running, every device in your house — smart TVs, phones, tablets, laptops — can stream your movies, TV shows, music, and photos without any subscription fees or your data leaving your home.
I remember the first time I got Jellyfin running. I had been using Plex for years, and the constant "Plex Pass required" messages for features like hardware transcoding and intro skipping were getting frustrating. Switching to Jellyfin felt liberating. Everything I had been paying for suddenly worked for free. But getting there took a few tries because most guides skipped over the parts that actually trip beginners up.
This guide is the one I wish I had back then. I will walk you through every step from absolute zero: installing Docker, writing your first Docker Compose file, setting up Jellyfin, organizing your media, enabling hardware transcoding, and securing remote access. No skipped steps, no assumed knowledge. If you can copy and paste a command, you can do this.
What is Jellyfin and Why Should You Care?
Before we get into installation, let me explain why Jellyfin is worth your time.
Jellyfin is a free, open-source media server. You install it on a computer in your home (a mini PC, an old laptop, a NAS), point it at a folder full of movies and TV shows, and it streams that content to any device on your network — or outside it if you set up remote access.
Here is what makes Jellyfin different from the alternatives:
Jellyfin vs Plex vs Emby
|---------|----------|------|------|
Why this matters: Every feature Jellyfin offers is free. Not a trial, not a "freemium" version — genuinely free. Hardware transcoding (which lets your server convert 4K video on the fly so your TV can play it) costs $120 with Plex. With Jellyfin, it is included. Intro skipping, downloads, remote access — all included.
If you are already using Plex or Emby, our Jellyfin vs Plex vs Emby comparison breaks down the differences in more detail. For this guide, I am assuming you are starting fresh.
What Hardware Do You Need?
Here is the good news: Jellyfin runs on almost anything.
Minimum requirements:
Recommended for smooth 4K streaming:
The magic ingredient is an Intel CPU with integrated graphics. The Intel N100 chip found in many budget mini PCs (Beelink EQ12/EQ14, Minisforum S12 Pro, or similar) can handle multiple 4K transcodes simultaneously while drawing less than 15 watts of power. That is roughly $15-20 per year in electricity to run your media server 24/7.
Why Intel over AMD for a media server? Intel's Quick Sync Video (QSV) technology is more mature and better supported in Linux and Docker. AMD integrated graphics work too, but Intel is the path of least resistance. If you are building a dedicated Jellyfin machine, an N100-based mini PC for around $180 is the sweet spot I recommend to everyone.
My recommended hardware picks:
If you already have a computer running 24/7 — even a Raspberry Pi 4 or 5 — Jellyfin will run on it. The Pi can stream 1080p content without issues; 4K will need hardware transcoding which the Pi can't do, but for most people 1080p is perfectly fine. Start with what you have.
Step 1: Install Docker and Docker Compose
If you do not have Docker installed yet, this is the first thing to do. Docker packages Jellyfin (and every other service you might run later) in a self-contained environment. Think of it like a shipping container for your software — everything the application needs is packed inside, and it runs identically on any computer.
Why Docker matters: Installing Jellyfin directly on your operating system ("bare metal") mixes its files with system files. Updates can break things, uninstalling leaves leftover files, and if you ever want to move Jellyfin to a different machine, you basically start from scratch. Docker solves all of that. Want to upgrade Jellyfin? One command. Want to move it to a new server? Copy one folder.
Open a terminal on your Linux machine (I am assuming Ubuntu or Debian, but the commands work on most distros):
# Download and run the official Docker installation script
curl -fsSL https://get.docker.com | sh
# Add your user to the docker group so you can run Docker without sudo
sudo usermod -aG docker $USER
# Apply the group change (or log out and back in)
newgrp docker
# Verify Docker is working
docker --version
docker compose version
If you see version numbers, Docker is installed. If `docker compose` gives a "command not found" error, install it separately:
sudo apt update
sudo apt install docker-compose-plugin
Do not worry if some of these commands look unfamiliar. Every homelabber started where you are now. Once Docker is installed, you never have to do this step again.
Step 2: Create Your Jellyfin Folder Structure
Jellyfin needs a few dedicated folders to store its configuration, cache, and transcoding temporary files. Let's set those up:
# Create a folder for all Jellyfin files
mkdir -p ~/jellyfin
# Move into it
cd ~/jellyfin
# Create subfolders for config and cache
mkdir -p config cache
That is it. Your folder structure looks like this:
~/jellyfin/
docker-compose.yml (we create this next)
config/ (Jellyfin settings and database)
cache/ (transcoding temporary files)
Why separate folders matter: The `config` folder holds your Jellyfin settings, user accounts, and media metadata. If you ever need to rebuild your server, you can keep this folder and all your setup survives intact. The `cache` folder holds temporary files from transcoding sessions — it can be thrown away at any time without losing anything important.
Step 3: Write Your Docker Compose File
This is the core of your setup. A Docker Compose file describes exactly how your Jellyfin container should run. It is a plain text file with a `.yml` extension.
Create `docker-compose.yml` inside your `~/jellyfin` folder:
nano docker-compose.yml
Then paste in the following content:
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000
restart: unless-stopped
network_mode: host
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/your/movies:/media/movies:ro
- /path/to/your/tvshows:/media/tv:ro
- /path/to/your/music:/media/music:ro
devices:
- /dev/dri:/dev/dri
group_add:
- 44
- 105
Let me explain each line so you understand what it does:
Important: Before you can run this, you need to edit the media paths. Replace `/path/to/your/movies`, `/path/to/your/tvshows`, and `/path/to/your/music` with the actual paths to your media on your computer.
If your movies are on an external drive mounted at `/mnt/external/movies`, your volumes section would look like:
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/external/movies:/media/movies:ro
- /mnt/external/tv:/media/tv:ro
If you only have movies and no TV shows or music yet, remove the lines you do not need. You can always add them later.
Step 4: Start Jellyfin
With your `docker-compose.yml` in place, start Jellyfin:
cd ~/jellyfin
docker compose up -d
The `-d` flag runs Jellyfin in the background ("detached mode"). Docker downloads the image the first time, which takes a minute or two depending on your internet speed.
Check that it started successfully:
docker compose ps
You should see output showing `jellyfin` with a status of `Up`. If you see `Exited`, something went wrong. Check the logs:
docker compose logs
Most startup issues come from:
If everything is running, open a web browser and go to:
http://YOUR_SERVER_IP:8096
Replace `YOUR_SERVER_IP` with your computer's IP address. If you are on the same computer running Jellyfin, use `http://localhost:8096`.
Step 5: Complete the Setup Wizard
The first time you open Jellyfin, you will see a setup wizard. It walks you through the essentials.
Step 5a: Choose your display language and set up your admin account.
Pick a strong password. This is the master key to your media server. I recommend a password manager-generated password since you will probably log in once and then use apps that remember it.
Step 5b: Add your first media library.
Click "Add Media Library" and choose the content type. For each library, set the folder path:
These paths match the ones you set in your `docker-compose.yml` file. Jellyfin sees them as `/media/movies` because that is how you mapped them inside the container.
For each library, you can also set:
Step 5c: Configure metadata language and country settings.
This tells Jellyfin where to download movie posters, descriptions, and ratings from. The defaults are fine for most people.
Step 5d: Enable remote access (optional for now).
You can skip remote access during setup and configure it later. We will cover that in Step 9.
Once the wizard finishes, the real magic happens: Jellyfin starts scanning your media library. Depending on how many files you have, this can take a few minutes to an hour. You will see posters and descriptions appearing as Jellyfin identifies each movie or show.
Step 6: Organize Your Media the Right Way
Here is the step most guides gloss over, and it is the one that causes the most frustration. Jellyfin identifies your media by its file and folder names. Get the naming right, and everything works automatically. Get it wrong, and you will see "Unknown" entries with no poster, no description, and no metadata.
Why naming matters: Jellyfin matches your files against online databases like The Movie Database (TMDB) and TheTVDB. It uses the file name and folder structure to identify what each piece of media is. If the name does not match their records, Jellyfin cannot identify it.
Movies folder structure:
/media/movies/
The Dark Knight (2008)/
The Dark Knight (2008).mkv
Inception (2010)/
Inception (2010).mp4
Parasite (2019)/
Parasite (2019).mkv
Rules for movies:
TV Shows folder structure:
/media/tv/
Breaking Bad/
Season 01/
Breaking Bad - S01E01 - Pilot.mkv
Breaking Bad - S01E02 - Cat's in the Bag.mkv
Season 02/
Breaking Bad - S02E01 - Seven Thirty-Seven.mkv
The Office (US)/
Season 01/
The Office (US) - S01E01 - Pilot.mkv
Rules for TV shows:
Common naming mistakes to avoid:
If you have a large existing collection with haphazard naming, tools like FileBot or Sonarr / Radarr can rename everything automatically. But for this guide, even manually renaming a few dozen files is worth the one-time effort.
Step 7: Enable Hardware Transcoding (The Game-Changer)
Hardware transcoding is the feature that turns a mediocre media server into a great one. Here is why it matters:
When you stream a video to your phone or TV, sometimes the device cannot play the original format. Your 4K HDR movie might be encoded in HEVC (a modern codec), but your tablet might only support H.264 (an older standard). Jellyfin needs to convert the video on the fly — this is called transcoding.
Without hardware transcoding, your CPU does all the work. A single 4K transcode can peg your CPU at 100%, making the server unresponsive and using a lot of power. With hardware transcoding, a dedicated chip on your Intel GPU handles the conversion using a fraction of the energy.
Step 7a: Check if your Intel GPU is accessible.
ls /dev/dri
If you see `card0` and `renderD128`, your Intel GPU is detected. If you see nothing, your CPU might not have integrated graphics, or the drivers are not loaded.
Also check which render group your system uses:
getent group render
Output looks like `render:x:105:` — the number (105 in this case) is the group ID. Make sure it matches the `group_add: - 105` line in your docker-compose.yml. If your system uses a different GID (some use 44), update the docker-compose.yml accordingly.
Step 7b: Configure transcoding in Jellyfin.
After saving, restart the container:
docker compose restart
Step 7c: Verify transcoding is working.
Play a 4K video on a device that cannot natively play it (a phone browser works well for testing). While it is playing, go back to the Jellyfin dashboard and check Dashboard → Playback → Active Transcoding Sessions. You should see it listed.
If transcoding is not working, check the logs:
docker compose logs jellyfin | grep -i "transcode\|qsv\|vaapi"
Common issues:
Step 8: Access Jellyfin on Your Devices
Once Jellyfin is running, you can watch your media from almost any device.
On your local network:
Open a browser on any device and go to `http://YOUR_SERVER_IP:8096`. Log in with the admin account you created during setup.
For a better experience, install the Jellyfin client app:
Pro tip: For the smoothest experience on your TV, use the Jellyfin app rather than the web browser. The apps are optimized for TV remote controls and direct play more formats without needing to transcode.
Step 9: Set Up Remote Access (Watch From Anywhere)
This is the step many beginners skip because it sounds complicated. But having Jellyfin accessible outside your home changes everything — watching your library at a friend's house, on vacation, or during lunch at work.
Why the VPN approach is safer: Opening ports on your home router to the internet is risky. Bots constantly scan for open ports and try to break in. A simpler and more secure approach that I recommend for beginners is using a VPN (like WireGuard) to access your home network remotely, then accessing Jellyfin as if you were home.
But if you want direct remote access, here is the simplest method:
Option A: Cloudflare Tunnel (Recommended for beginners)
Cloudflare Tunnel creates a secure tunnel from your server to Cloudflare's network. No open ports on your router required.
# Add this to your docker-compose.yml under services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel run
environment:
- TUNNEL_TOKEN=your-tunnel-token-here
You need a Cloudflare account and a domain, but the free tier handles this perfectly. Cloudflare provides detailed guides on setting up the tunnel token.
Option B: Reverse Proxy with Caddy (For your own custom domain)
Caddy is a web server that automatically handles HTTPS certificates. Add it to your docker-compose.yml:
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
depends_on:
- jellyfin
volumes:
caddy_data:
Then create a `Caddyfile` in your jellyfin folder:
media.yourdomain.com {
reverse_proxy jellyfin:8096
}
Replace `media.yourdomain.com` with a domain you own, pointed to your server's IP. Caddy automatically obtains a free SSL certificate from Let's Encrypt.
Option C: Tailscale (Easiest for personal use)
Tailscale creates a secure mesh VPN between all your devices. It takes 5 minutes to set up and requires no port forwarding at all. Install Tailscale on your server and all your devices, and you can access Jellyfin at `http://jellyfin-tailscale-ip:8096` from anywhere.
I personally recommend Tailscale for beginners. It is free for personal use, incredibly simple, and is more secure than opening ports. The only tradeoff is that guests cannot access your Jellyfin without installing Tailscale too — but for personal use, that is a feature, not a bug.
Common Mistakes (and How to Fix Them)
After helping several friends set up their first Jellyfin servers, here are the mistakes I see most often:
1. Permission issues with media folders.
Jellyfin cannot read your media if it does not have permission. Your docker-compose.yml sets `user: 1000:1000` — this must match your user ID. Run `id` to check. And ensure your media folders are readable: `chmod -R a+r /path/to/media`.
2. Incorrect media naming.
This is the number one frustration. Jellyfin identifies media by filename, not by scanning file contents. If you have a movie named `My_Home_Video_2024.mp4`, Jellyfin will try to find it on TMDB and fail. Use the naming convention in Step 6 and your metadata will download automatically.
3. No hardware transcoding configured.
Without hardware transcoding, your CPU will struggle with 4K content. Even a modern i5 can be pegged at 100% by a single 4K transcode. Set up Intel Quick Sync from the start — it takes 5 minutes and saves so much frustration.
4. Forgetting to restart after config changes.
You changed the docker-compose.yml but nothing happened. Run `docker compose down && docker compose up -d` to apply the changes. Just editing the file does nothing until you re-create the container.
5. Using Wi-Fi for the server.
Jellyfin needs a stable, wired network connection. Wi-Fi introduces buffering, especially for 4K content. Plug your server into your router with an Ethernet cable. The difference is immediately noticeable.
6. Not backing up the config folder.
Your `config` folder contains all your settings, user accounts, watch history, and metadata. If you lose it, you start over. Back it up regularly. Our Docker backup strategies guide shows you how to automate this.
7. Using the `:latest` tag without pinning.
This is a personal preference, but I recommend pinning your Jellyfin version once you have it working well. Change `jellyfin/jellyfin:latest` to `jellyfin/jellyfin:10.9.0` (or whatever the current stable version is). This prevents unexpected updates that might change something you rely on. You can bump the version when you are ready to update.
What to Learn Next
Setting up Jellyfin is just the beginning. Your media server can become the hub of your homelab. Here are some natural next steps:
Automate media downloads with the *arr stack* — Sonarr (TV shows), Radarr (movies), Prowlarr (indexer management), and SABnzbd or qBittorrent (download clients). These apps integrate with Jellyfin, so new content appears automatically in your library.
Set up comprehensive backups for your Jellyfin config and media. Our Docker backup strategies guide shows you how to back up everything automatically.
Explore other self-hosted services on the same server. With Docker, you can run a password manager, a photo gallery, and a home automation system all on the same hardware. Check out what to self-host first for inspiration.
Harden your server's security with a reverse proxy, fail2ban, and proper firewall rules. Our homelab security guide is a good starting point.
Monitor your server's health so you know if it goes down. Simple uptime monitoring with tools like Uptime Kuma can alert you when Jellyfin stops responding.
Frequently Asked Questions
Is Jellyfin really completely free? No hidden costs?
Yes, completely free. Jellyfin is open-source software released under the MIT license. There are no paid tiers, no subscription plans, no premium features locked behind paywalls. Hardware transcoding, intro skipping, downloads, remote access — all included. The developers maintain it through donations, not paywalls.
Do I need a powerful computer to run Jellyfin?
Not at all. Jellyfin runs on a Raspberry Pi 4 (1080p streaming), an old laptop, or a cheap mini PC. For 4K content, you want Intel 8th-gen or newer CPU with Quick Sync Video (like the N100/N150 found in $180 mini PCs). But for 1080p content, anything from the last 10 years will work.
Can I keep using Plex and try Jellyfin at the same time?
Yes. They can run side by side on the same computer pointing at the same media folders. I did exactly this for a month before switching fully. The only thing to watch out for is both servers trying to use the same port — make sure Jellyfin uses 8096 (its default) and Plex uses 32400 (its default), and they won't conflict.
How do I update Jellyfin when a new version comes out?
With Docker, updating is two commands:
docker compose pull
docker compose up -d
That is it. Your config and settings are preserved in the `config` folder. I recommend checking the Jellyfin release notes before updating, especially for major version bumps.
Can Jellyfin stream outside my home without opening ports?
Absolutely. Cloudflare Tunnel, Tailscale, and ZeroTier all provide remote access without opening any ports on your router. Cloudflare Tunnel requires a domain but gives you a public URL. Tailscale creates a private network between your devices. For personal use, Tailscale is the simplest option.
*David Okonkwo is a DevOps engineer and open-source advocate who transitioned from web development to self-hosting. He believes everyone should own their data, starting with their media library. When he is not writing tutorials, he is probably tweaking his homelab config or helping someone set up their first Docker container.*
