Mad World #Save_GAZA: Free Palestine  

Search

How to Install Jellyfin with Docker Compose (2026 Step-by-Step Guide)

How to Install Jellyfin with Docker Compose (2026 Step-by-Step Guide)

Jellyfin is a free, open-source media server. It puts your movies, shows and music in one library, with posters and summaries, and streams them to a browser, a phone or a TV. You host it yourself: no account with a company, no subscription.

This guide installs Jellyfin with Docker Compose on a Linux machine, runs the setup wizard and plays a first movie. It also explains the Jellyfin ports, updates, backups and the errors that you are most likely to meet.

We tested every step on 13 November 2026 in a disposable lab: Jellyfin 12.4.0 (the jellyfin/jellyfin:latest image of 26 October 2026), Docker Engine 29.9.3 and Docker Compose v5.7.1. Our test movie is Big Buck Bunny, the free open movie of the Blender Foundation.

Which ports does Jellyfin use?

Jellyfin uses port 8096 for its web interface and streaming. The other two ports are optional:

PortProtocolUsed forDo you need it?
8096TCPWeb interface, apps and streaming over HTTP (the default)Yes
8920TCPHTTPS, only after you enable it in Jellyfin and give it a certificateOnly for Jellyfin's own HTTPS
7359UDPLets the Jellyfin apps find the server on your local networkOptional, local network only

The Jellyfin documentation adds that DLNA needs host networking (network_mode: host). This guide uses the default bridge network, which is enough for the browser and the apps.

To use another port, change only the left side of the mapping in the Compose file, for example "8097:8096/tcp", then open http://your-server-ip:8097. Inside the container, Jellyfin stays on 8096. The same numbers are in the Dashboard, under Networking:

Jellyfin Dashboard Networking page with Local HTTP port number 8096 and Local HTTPS port number 8920
Dashboard → Networking: (1) the HTTP port 8096, (2) the HTTPS port 8920, used only when "Enable HTTPS" is on.

What you need

  • A Linux machine with Docker Engine and the Compose plugin. No Docker yet? Follow our guide to install Docker and Docker Compose on Ubuntu. New to containers? Read Docker for beginners first.
  • Your movies or shows on a disk of that machine.
  • Port 8096 free on that machine.
  • At least 2 GiB free for the Jellyfin config folder. Jellyfin checks this at every start.

On Windows and macOS, the Jellyfin project tells you to install Jellyfin natively. In a container on these systems, features such as hardware-accelerated transcoding do not work, and the project gives no support.

If your user is not in the docker group, put sudo in front of every docker command below.

Step 1: Create the folders

Jellyfin uses three places:

  • config: the settings, the users, the library database and the downloaded posters. This is the folder to back up.
  • cache: temporary files, such as resized images and transcoded video. Jellyfin can rebuild it.
  • Your media folder. In this guide: /srv/media, with the movies in /srv/media/movies.
Terminal
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo mkdir -p /srv/media/movies
sudo chown -R $(id -u):$(id -g) /srv/media

Now check your user ID (uid) and group ID (gid). Jellyfin will run with them, so that it can write to its folders:

Code
id
Code
uid=1000(igprod) gid=1000(igprod) groups=1000(igprod),2375(docker)
Terminal
ls -ld ~/jellyfin/config ~/jellyfin/cache /srv/media/movies
Code
drwxr-sr-x    2 igprod   igprod        4096 Nov 13 13:25 /home/igprod/jellyfin/cache
drwxr-sr-x    2 igprod   igprod        4096 Nov 13 13:25 /home/igprod/jellyfin/config
drwxr-xr-x    2 igprod   igprod        4096 Nov 13 13:25 /srv/media/movies

Our user has the IDs 1000 and 1000, which is usual for the first user of a Linux machine. If yours are different, use your numbers in step 2.

Put each movie in its own folder, named with the title and the year. Jellyfin uses these names to find the right poster and summary:

Code
/srv/media/movies/Big Buck Bunny (2008)/Big Buck Bunny (2008).mp4

Step 2: Write the compose.yaml file

Go to the Jellyfin folder and create the file:

Terminal
cd ~/jellyfin
nano compose.yaml

Paste this content. It is the official example of the Jellyfin documentation, with the paths of step 1:

YAML
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: "1000:1000"
    ports:
      - "8096:8096/tcp"
      - "7359:7359/udp"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - type: bind
        source: /srv/media
        target: /media
        read_only: true
    restart: unless-stopped
  • image: jellyfin/jellyfin:latest: the official image. latest follows the newest stable release. To stay on one version line, use a tag such as jellyfin/jellyfin:12.4.
  • user: "1000:1000": Jellyfin runs as your user, not as root. Keep the quotes.
  • 8096:8096/tcp: the web interface. 7359:7359/udp: discovery by the apps on your local network. You can remove that line if you do not need it.
  • ./config and ./cache: the two folders of step 1, next to the Compose file.
  • The bind mount shows your media folder inside the container as /media. With read_only: true, Jellyfin can read your files but cannot change or delete them.
  • restart: unless-stopped: Docker starts Jellyfin again after a reboot, unless you stopped it yourself.

Step 3: Start Jellyfin

Terminal
docker compose up -d
Code
 Network jellyfin_default Creating 
 Network jellyfin_default Created 
 Container jellyfin Creating 
 Container jellyfin Created 
 Container jellyfin Starting 
 Container jellyfin Started
Terminal
docker compose ps
Code
NAME       IMAGE                      COMMAND                SERVICE    CREATED          STATUS                    PORTS
jellyfin   jellyfin/jellyfin:latest   "/jellyfin/jellyfin"   jellyfin   21 seconds ago   Up 20 seconds (healthy)   0.0.0.0:7359->7359/udp, [::]:7359->7359/udp, 0.0.0.0:8096->8096/tcp, [::]:8096->8096/tcp

Wait until the status says (healthy). In our lab, Jellyfin started in less than 10 seconds. The log confirms it, and shows the FFmpeg build that comes with the image:

Terminal
docker logs jellyfin 2>&1 | grep -E "FFmpeg:|Startup complete"
Code
[13:40:22.075] [INF] [10] MediaBrowser.MediaEncoding.Encoder.MediaEncoder: FFmpeg: /usr/lib/jellyfin-ffmpeg/ffmpeg
[13:40:22.076] [INF] [10] Main: Startup complete 0:00:05.1192869

You can also ask the server directly:

Terminal
curl -s http://localhost:8096/health
curl -s http://localhost:8096/System/Info/Public | grep -o '"Version":"[^"]*"'
Code
Healthy
"Version":"12.4.0"

Step 4: Run the setup wizard

Open http://your-server-ip:8096 in a browser. On the server itself, http://localhost:8096 also works. The wizard starts by itself.

Name the server and choose the language

Jellyfin setup wizard Welcome page with Server name, Preferred display language and Next
The first page: (1) a name for the server, (2) the language of the interface, (3) Next.

By default, the server name is the host name of the container, a random ID. Give it a name that you will recognize in the apps. We used Home Media.

Create the admin user

Jellyfin setup wizard Tell us about yourself page with Username, Password and Password confirm
(1) Your user name, (2) and (3) a strong password, twice, (4) Next.

Jellyfin proposes the name MyJellyfinUser: replace it with your own. A password is required for the admin account. You can add the other users of your home later, in the Dashboard.

Add your movie library

Click Add Media Library. Choose Movies as content type and type a display name. Then click + next to Folders. The Select Path window shows the folders of the container, not the folders of your server. Type /media/movies, the path of step 2, and click OK:

Jellyfin Select Path window with the folder /media/movies typed in and the OK button
Inside the container, your media folder is /media: (1) type /media/movies, (2) OK.
Jellyfin Add Media Library window with content type Movies, display name Movies and the folder /media/movies
The library: (1) content type Movies, (2) its name, (3) the folder that you just added.

Before you click OK, scroll down and clear Save subtitles into media folders. It is on by default, but our media folder is read-only, so Jellyfin could not save subtitles there. It then keeps them in its own folders. Click OK: the library appears on the page.

Jellyfin setup wizard media libraries page with the Movies library and its folder /media/movies
(1) The Movies library with its folder, (2) Next.

Choose the metadata language

Jellyfin setup wizard Preferred Metadata Language page with English and United States
Jellyfin downloads titles, summaries and posters in (1) this language, (2) for this country, (3) Next.

Remote access

Jellyfin setup wizard Set up Remote Access page with Allow remote connections to this server checked
(1) Allow remote connections to this server, on by default, (2) Next.

The wizard explains: "If unchecked, all remote connections will be blocked." Leave it on if you want to watch from outside your home later, through a VPN or a reverse proxy (see below). The option does not open anything on your router.

Finish

Jellyfin setup wizard You are Done page with the Finish button
Click Finish. Jellyfin starts to read your library in the background.

Step 5: Sign in and play your first movie

Jellyfin Please sign in page with User, Password and Sign In
Sign in with (1) the user and (2) the password of the wizard, then (3) Sign In.

The home page shows your libraries and the latest movies. Jellyfin found the poster and the details of our test movie from its folder name alone:

Jellyfin home page with the Movies library and Big Buck Bunny in Recently Added in Movies
(1) The Movies library, (2) the movie that Jellyfin found, with its poster. Big Buck Bunny © 2008 Blender Foundation, peach.blender.org, CC BY 3.0.
Jellyfin movie page of Big Buck Bunny with poster, summary, video and audio details and the Play button
The movie page: year, length, video and audio formats, summary and cast. (1) Play. Big Buck Bunny © 2008 Blender Foundation, peach.blender.org, CC BY 3.0.
Big Buck Bunny playing in the Jellyfin web player
The movie plays in the browser. Big Buck Bunny © 2008 Blender Foundation, peach.blender.org, CC BY 3.0.

The browser played the file directly, without transcoding: its H.264 video and AAC audio are formats that the browser reads. When a device cannot read a format, Jellyfin converts the video while it plays. That is transcoding, and it needs much more processor power.

Run Jellyfin with docker run instead

If you do not use Compose, this one command creates the same container. We tested it with the same folders:

Terminal
docker run -d --name jellyfin --user 1000:1000 \
  -p 8096:8096/tcp -p 7359:7359/udp \
  -v ~/jellyfin/config:/config -v ~/jellyfin/cache:/cache \
  --mount type=bind,source=/srv/media,target=/media,readonly \
  --restart=unless-stopped jellyfin/jellyfin:latest
Terminal
docker ps --format "{{.Names}} {{.Status}} {{.Ports}}"
Code
jellyfin Up 24 seconds (healthy) 0.0.0.0:7359->7359/udp, [::]:7359->7359/udp, 0.0.0.0:8096->8096/tcp, [::]:8096->8096/tcp

Do not run both versions at the same time: they use the same container name and the same port. The Compose file is easier to keep, update and share, which is why we use it in this guide. To learn more, read what Docker Compose is and why it helps.

Update Jellyfin

Terminal
cd ~/jellyfin
docker compose pull && docker compose up -d
Code
 Image jellyfin/jellyfin:latest Pulling 
 Image jellyfin/jellyfin:latest Pulled 
 Container jellyfin Running

When the registry has a newer image, Compose downloads it and creates the container again. Your config folder stays, so your users and libraries stay too. On our test day, the image was already the newest, so the container kept running.

Before an update to a new version line, back up the config folder (next section) and read the release notes.

Back up and restore Jellyfin

Stop Jellyfin, save the config folder in an archive, and start Jellyfin again. The cache folder can be rebuilt, and your media files have their own backups:

Terminal
cd ~/jellyfin
docker compose stop && tar czf ~/jellyfin-config-backup.tgz -C ~/jellyfin config && docker compose start
ls -lh ~/jellyfin-config-backup.tgz
Code
 Container jellyfin Stopping 
 Container jellyfin Stopped 
 Container jellyfin Starting 
 Container jellyfin Started 
3.1M /home/igprod/jellyfin-config-backup.tgz

Our archive was 3.1 MB with one movie. With a big library and its posters, expect much more. Copy the archive to another disk or machine.

To restore, stop and remove the container, keep the current folder aside, extract the archive, and start again:

Terminal
cd ~/jellyfin
docker compose down
mv config config.before-restore
tar xzf ~/jellyfin-config-backup.tgz -C ~/jellyfin
docker compose up -d
Code
 Container jellyfin Stopping 
 Container jellyfin Stopped 
 Container jellyfin Removing 
 Container jellyfin Removed 
 Container jellyfin Creating 
 Container jellyfin Created 
 Container jellyfin Starting 
 Container jellyfin Started

We checked the result: the wizard did not start again, our user could sign in, and the API listed the same library and movie:

Code
"Name":"Movies"
"Locations":["/media/movies"]
"Name":"Big Buck Bunny"

Jellyfin 12.4 also has a Backups page in the Dashboard. We tested the folder backup above because it works with any version and needs nothing more than tar.

Hardware acceleration

Transcoding with the processor alone is slow, above all for 4K video. Jellyfin can use a graphics chip instead: Intel Quick Sync, AMD or NVIDIA. The image comes with its own FFmpeg build that supports these methods. At start, our log listed cuda, vaapi, qsv, drm, opencl, vulkan and amf.

To use them, the container needs access to the graphics device (for Intel and AMD, /dev/dri), and you choose the method in the transcoding settings of the Dashboard. We did not test this part: our lab has no graphics chip. Follow the hardware acceleration page of the Jellyfin documentation for your hardware.

Watch from outside your home, safely

Do not forward port 8096 on your router. The Jellyfin documentation itself says that opening a port directly to the internet is insecure and not recommended. Two safer ways:

  • A VPN such as WireGuard or Tailscale. Your phone joins your home network, and you open Jellyfin as at home. Nothing is public.
  • A reverse proxy with HTTPS, such as Nginx Proxy Manager, in front of Jellyfin. Then add the address of the proxy in Known proxies on the Networking page, so that Jellyfin sees the real address of each visitor. Our guide to fix the real IP behind Nginx Proxy Manager explains why this matters.

Troubleshooting

"Bind for 0.0.0.0:8096 failed: port is already allocated"

Another container already uses port 8096. We got this error when we started a second container on the same port:

YAML
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint port-test (…): Bind for 0.0.0.0:8096 failed: port is already allocated

Find the other container with docker ps. Emby, for example, also uses 8096. Stop it, or publish Jellyfin on another host port, for example "8097:8096/tcp". Our Emby vs Jellyfin trial runs both servers side by side this way.

"Access to the path '/config/log' is denied"

Jellyfin cannot write to its config folder. We reproduced it with a folder created by root while Jellyfin runs as the user 1000. The container stops at once with:

Code
Unhandled exception. System.UnauthorizedAccessException: Access to the path '/config/log' is denied.
 ---> System.IO.IOException: Permission denied

Give the folders to the user of your Compose file, then start again:

Terminal
sudo chown -R 1000:1000 ~/jellyfin/config ~/jellyfin/cache
docker compose up -d

The library stays empty

Look at the folder from inside the container, with the path that Jellyfin sees:

Terminal
docker exec jellyfin ls -l /media/movies "/media/movies/Big Buck Bunny (2008)"
Code
/media/movies:
total 4
drwxr-xr-x 2 1000 1000 4096 Nov 13 13:28 Big Buck Bunny (2008)

/media/movies/Big Buck Bunny (2008):
total 63144
-rw-r--r-- 1 1000 1000 64657027 Nov 13 13:28 Big Buck Bunny (2008).mp4

If the list is empty, the bind mount points to the wrong folder of your server: check source in the Compose file. If you get Permission denied, the files are not readable by the user 1000. When the files are visible, start a new scan of the library from the Dashboard.

Frequently asked questions

What port does Jellyfin use?

Port 8096 (TCP) for the web interface and streaming. Port 8920 (TCP) is for HTTPS, only when you enable it in Jellyfin. Port 7359 (UDP) lets the apps find the server on your local network.

Is Jellyfin free?

Yes. Jellyfin is free and open source, with no paid plan and no premium features. You only pay for the machine that runs it.

Should I use jellyfin/jellyfin or linuxserver/jellyfin?

jellyfin/jellyfin is the official image, built by the Jellyfin project from its source code (also on ghcr.io/jellyfin/jellyfin). The LinuxServer.io and hotio images are made by third parties, from the official Ubuntu packages. All of them work. This guide uses the official one.

Can I run Jellyfin in Docker on Windows or macOS?

It can start, but the Jellyfin project does not support it, and features such as hardware-accelerated transcoding do not work. On these systems, install Jellyfin natively.

Where does Jellyfin keep its data?

In the config folder: settings, users, watch history, the library database and the posters. The cache folder holds temporary files. Your media files stay where they are, untouched.

Can Jellyfin and Plex run on the same machine?

Yes. Plex uses port 32400 and Jellyfin 8096, so they do not collide, and both can read the same media folder. Not sure which one to keep? Read our Jellyfin vs Plex comparison.

Sources

Salah Edin

Salah Edin

Salah Edin covers security advisories, Linux and DevOps for IGPROD.

Leave a comment

Your email address will not be published. Required fields are marked *

Your experience on this site will be improved by allowing cookies Cookie Policy