Install Jellyfin with Docker Compose on Ubuntu 24.04 LTS

Jellyfin is one of the most practical self-hosted apps you can run if you want your movies, shows, and music on infrastructure you actually control. It gives you a polished web interface, user accounts, library management, metadata fetching, and streaming without handing your collection to somebody else’s platform.

In this guide, you will deploy Jellyfin with Docker Compose on Ubuntu Server 24.04 LTS, mount a media library and persistent app data, start the container, and complete the first browser-based setup so you can begin building your library.

OS used in this tutorial

This walkthrough is written against Ubuntu Server 24.04 LTS.

That matters because the host-side setup in this guide assumes Ubuntu-style package management, Docker installation habits, filesystem layout, and firewall behavior. The Jellyfin container itself is portable, but the surrounding server steps are not always identical across Debian, Fedora, AlmaLinux, Rocky Linux, or older Ubuntu releases.

If you are using another distro, treat this as a close reference rather than a promise that every command is identical.

Jellyfin’s docs explain the container deployment and networking behavior, but they do not publish a simple one-size-fits-all beginner hardware chart for every media workload. Real requirements depend heavily on your library size, whether clients can direct play, and whether the server must transcode video on the fly.

Here is a practical starting point.

Minimum

  • 2 vCPU

  • 2 GB RAM

  • 20 GB SSD storage for the OS, Jellyfin config, cache, and metadata

  • separate storage for your actual media library

This is workable for a small test library or a light direct-play setup with one user at a time.

  • 4 vCPU

  • 4 to 8 GB RAM

  • 40 GB or more fast storage for the OS, metadata, cache, and growth

  • media stored on a larger disk, attached volume, or well-planned network path

This is a more comfortable starting point if you want a real library, multiple users, or occasional transcoding.

If you expect frequent transcoding, large 4K files, or multiple concurrent remote streams, size above that and think about GPU support early. Jellyfin is friendly, but video transcoding can turn a tiny server into a space heater with ambition.

Before you start

Have these ready first:

  • an Ubuntu Server 24.04 LTS machine or VPS

  • SSH access to that server

  • Docker installed and working

  • the Docker Compose plugin available as docker compose

  • a folder or disk path that already holds, or will hold, your media files

If you still need the container basics, start here first:

A quick note about where Jellyfin works best

You can run Jellyfin on a VPS, but it is not always the best first choice.

For a remote VPS deployment, think about:

  • upload bandwidth if you are streaming over the internet

  • storage cost if your library is large

  • whether your provider allows or throttles heavier media workloads

  • whether you will need hardware transcoding later

If your media files already live at home, a homelab server, mini PC, or other always-on local box can be a cleaner fit. Still, if your library is small and your goal is a simple self-hosted media server, a VPS can absolutely work.

How this Docker Compose setup works

For a beginner-friendly first deployment, I recommend keeping the stack simple:

  • one jellyfin container

  • one bind mount for persistent config

  • one bind mount for persistent cache

  • one bind mount for your media library

  • one published HTTP port on 8096

Jellyfin’s official container docs also mention optional UDP discovery on port 7359. That matters more on local networks for client discovery. For a basic server setup, the web interface on 8096 is the important part.

Step 1: Connect to your server

Use SSH from your local machine.

ssh your-user@your-server-ip

Replace your-user with your Ubuntu username and your-server-ip with the server’s public IP address.

Step 2: Create folders for the Jellyfin stack

Create a dedicated app directory.

sudo mkdir -p /opt/jellyfin

Give your regular user ownership of it.

sudo chown "$USER":"$USER" /opt/jellyfin

Move into it.

cd /opt/jellyfin

Create folders for persistent Jellyfin data.

mkdir -p config
mkdir -p cache

This guide assumes your media library will live at /srv/media. Create that path now if you need a starter location.

sudo mkdir -p /srv/media

If you created the folder yourself and want your normal user to manage it directly, hand over ownership.

sudo chown "$USER":"$USER" /srv/media

If your media already lives somewhere else, keep that path instead and adjust the Compose file in the next step.

Step 3: Create the compose.yaml file

Save this as compose.yaml inside /opt/jellyfin.

cat > compose.yaml <<'EOF'
services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.11
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "8096:8096"
    environment:
      - JELLYFIN_PublishedServerUrl=http://YOUR_SERVER_IP:8096
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /srv/media:/media
EOF

What the important lines do

image: jellyfin/jellyfin:10.11.11

Jellyfin’s official container docs support version-specific tags, major-version tags, minor-version tags, and latest. I am pinning this to the current stable release surfaced by the upstream release feed so the guide stays reproducible.

"8096:8096"

Jellyfin’s networking docs list 8096/TCP as the default HTTP port for the web frontend. That is the port you will open in your browser for the first login.

JELLYFIN_PublishedServerUrl=http://YOUR_SERVER_IP:8096

Jellyfin documents this as an optional published server URL. For a simple first setup, it helps the app advertise the address you expect clients to use.

Replace YOUR_SERVER_IP with your actual server IP address before you start the container. If you already have a domain and reverse proxy ready, use that final URL instead.

./config:/config

This keeps Jellyfin’s persistent configuration outside the container so it survives upgrades and restarts.

./cache:/cache

This stores cache and generated runtime data outside the container too.

/srv/media:/media

This is the important library mount. Jellyfin will scan whatever media you place under that host path.

If your files live somewhere else, change /srv/media to the real host path.

Step 4: Review the file before you start

A couple of details are worth a last check:

  • the IP or domain in JELLYFIN_PublishedServerUrl is correct

  • the media path on the left side of /srv/media:/media is real on your server

  • the host has permission to read the media files you want to expose

This is one of those small review steps that saves bigger cleanup later.

Step 5: Start Jellyfin

Bring the container up in the background.

docker compose up -d

The first run may take a minute while Docker pulls the image.

Step 6: Check that the container is running

docker compose ps

You should see the jellyfin service running.

If the container exits or keeps restarting, inspect the logs.

docker compose logs --tail=100 jellyfin

Common early problems are usually one of these:

  • the media path does not exist

  • the server cannot read the mounted files

  • a host firewall or provider firewall is blocking the port

Step 7: Open Jellyfin in your browser

Jellyfin’s networking docs list 8096 as the default HTTP web port, so open this in your browser and replace the IP with your real server address:

http://YOUR_SERVER_IP:8096

If you used a domain or reverse proxy from the beginning, open that URL instead.

On first launch, Jellyfin should show the welcome and setup screens. If it asks for a server, just add your ip address:8096 and hit Connect.

Step 8: Complete the first-run setup

The setup wizard is straightforward, but a few choices matter.

Create your admin account

Choose your first administrator username and password.

Pick your preferred language and metadata language

Set the language choices that best match your library and your users.

Add your first media library

When Jellyfin asks for a content path, you will point it to the container path, not the host path.

That means if your host bind mount is /srv/media:/media, inside Jellyfin you should browse to folders under:

/media

For example, if your host has:

/srv/media/movies

then Jellyfin will see it as:

/media/movies

That path mapping trips people up all the time, so it is worth calling out before the wizard sends you on a little scavenger hunt.

Step 9: Finish setup and verify the dashboard loads

After the wizard finishes, Jellyfin should land on the main dashboard or home screen.

If your library folders already contain media, metadata scanning will begin shortly after setup.

Step 10: Make sure Ubuntu is not blocking the port

If the browser cannot reach Jellyfin but the container is running, check whether UFW is enabled.

sudo ufw status

If UFW is active, allow Jellyfin’s HTTP port.

sudo ufw allow 8096/tcp

If your provider also has a cloud firewall or security group, allow the same port there too.

A raw port is fine for a first test, but it is not my favorite long-term setup for a media app you plan to reach remotely.

A cleaner next step is putting Jellyfin behind a reverse proxy with a domain and HTTPS:

That gives you a nicer URL, easier certificate management, and a more polished remote-access path.

Updating Jellyfin later

When you want to update Jellyfin, return to /opt/jellyfin and pull the newer image before restarting the stack.

docker compose pull
docker compose up -d

If you pinned a specific version tag in the Compose file, update that tag first.

Final thoughts

Jellyfin is one of those projects that rewards a clean first setup. Keep the library path simple, keep the config persistent, and do not overcomplicate the stack on day one.

Once the basics are working, you can add a reverse proxy, stronger remote access rules, more libraries, and eventually hardware transcoding if your server and workload call for it. The first win is just getting your own media server online without it turning into a weekend-long side quest.

Frequently Asked Questions

Is a VPS a good place to run Jellyfin?
Sometimes, but it depends on your media and your network. Jellyfin works best when the server has fast storage, enough upload bandwidth, and ideally direct access to the media library. For home libraries, many people prefer a homelab box or NAS-adjacent server instead of a tiny remote VPS.
Do I need hardware transcoding on day one?
No. Jellyfin can work fine without it for direct-play friendly media and a small number of users. Hardware transcoding becomes more important when your files need frequent format conversion or you expect multiple remote streams.
Should I expose Jellyfin directly to the internet?
It is better to put it behind a reverse proxy with HTTPS if you want remote access. A raw open port is okay for a quick trusted-network test, but a proper domain and TLS setup is the cleaner long-term path.
share

Was this article helpful?

Let me know so I can keep improving.

Related articles

🚀
CI/CD & DevOps
Install Gitea with Docker Compose on Ubuntu 24.04 LTS
Install Gitea with Docker Compose on Ubuntu 24.04 LTS, keep repositories persistent, and finish the first setup with working web and SSH clone access.
☁️
File & Cloud Storage
How to Install Nextcloud with Docker Compose
Install Nextcloud with Docker Compose using MariaDB and Redis, keep the data persistent, and finish the first web setup without turning the stack into a science project.
🔒
Security & Firewalls
Set Up a WireGuard VPN on Ubuntu 24.04 LTS
Set up a WireGuard VPN on Ubuntu 24.04 LTS, create a server and client profile, and route your traffic through a fast self-hosted tunnel.
🤖
AI & LLMs
How to Install Open WebUI with Docker Compose
Install Open WebUI with Docker Compose on a Linux server, connect it to an Ollama container, and get a private browser-based chat interface running with persistent storage and a clean upgrade path.