# How to set up a personal Jellyfin server with Docker on Ubuntu

Running your own Jellyfin server is a great way to keep all your movies, TV shows, music and photos in one place and stream them whenever you want. Instead of relying on external streaming services, you stay in full control of your files, user accounts and who can access your content across your devices.

## What is Jellyfin?

Jellyfin is an [open-source](https://www.ionos.com/digitalguide/server/know-how/what-is-open-source/) media server that lets you **organize and manage your own media collection** and stream it to different devices through a browser or app. It supports common media types like movies, TV shows, music, and photos, and includes features like user accounts, metadata, cover art, playback tracking and streaming over your network.

Because Jellyfin server is self-hosted, it runs **independently of external providers**. You only need an internet connection for things like downloading metadata or enabling remote access. Inside your home network, Jellyfin uses HTTP on port 8096 by default. You can also enable [HTTPS](https://www.ionos.com/digitalguide/hosting/technical-matters/what-is-https/) if needed. For external access, the official documentation recommends using a reverse proxy with trusted certificates.

## Which server requirements do you need for Jellyfin?

Before installing Jellyfin, it’s worth taking a moment to choose the right server setup. It’s not just about how many files you want to store. What really matters is whether your devices can play those files directly or if the server needs to convert them during playback. That conversion process is called **transcoding**, and it can use a lot of resources. Things like 4K content, HDR-to-SDR tone mapping, or multiple streams at the same time can quickly put pressure on your [CPU](https://www.ionos.com/digitalguide/server/know-how/cpu/) or GPU.

For **typical setups**, Jellyfin recommends at least 8 GB of [RAM](https://www.ionos.com/digitalguide/server/know-how/what-is-ram/). If you’re running a lean Linux server without a graphical interface, 4 GB may be enough. For hardware acceleration on non-Apple systems, Intel graphics are usually the easiest option to work with and offer solid encoding performance.

Let’s look at a few different scenarios so you can see which setup makes the most sense for your needs.

### Individuals and families

If you’re mostly using Jellyfin on your own or with 2 or 3 other people and your files are already in common [video formats](https://www.ionos.com/digitalguide/websites/web-design/video-formats/) like **MP4 with H.264**, a [VPS](https://www.ionos.com/servers/vps "Rent an affordable VPS from IONOS") is often all you need. In this setup, the server mainly delivers files instead of converting them every time you press play. A solid starting point is a Linux VPS with at least 4 vCores, 4 GB RAM and around 120 GB of NVMe storage. If you want a bit more breathing room for larger libraries, metadata, or occasional transcoding, 6 vCores, 8 GB RAM, and 240 GB NVMe storage will feel more comfortable.

The biggest advantage here is the **cost-to-performance ratio**. You get enough power for a personal media server without needing to invest in dedicated hardware right away. This works especially well if your devices can already handle modern formats and rarely need transcoding.

### Advanced users

If your media library is growing, you want to manage multiple users, or you’d like more flexibility, [cloud servers](https://www.ionos.com/digitalguide/server/know-how/what-is-a-cloud-server/) or [Cloud Cubes](https://cloud.ionos.com/compute/cloud-cubes "IONOS Cloud Cubes") are a great option. You can start with around 4 vCPUs, 8 GB RAM, and 240 GB of storage. That gives you enough headroom for parallel scans, metadata processing, larger libraries and occasional transcoding.

The main benefit here is **flexibility**. You can easily scale your setup as your needs change. That’s useful if you want to start small and expand later, for example by adding more users, more libraries, or additional services like a [reverse proxy](https://www.ionos.com/digitalguide/server/know-how/what-is-a-reverse-proxy/), monitoring, or [backup](https://www.ionos.com/digitalguide/server/security/what-is-a-backup/). For advanced users, small teams, or homelab setups, this is often a comfortable middle-ground.

### High-performance and 4K setups

If you’re working with a large 4K library, need HDR-to-SDR conversion, or want to support multiple users streaming at the same time, a small VPS will run into performance issues fairly quickly. Jellyfin points out that **software-based HDR-to-SDR tone mapping can be extremely CPU-intensive**. In these cases, a [dedicated](https://www.ionos.com/servers/dedicated-servers "Dedicated Server from IONOS") or [bare metal](https://www.ionos.com/servers/bare-metal-servers "Bare Metal Server from IONOS") server makes much more sense. You get dedicated hardware and **don’t have to share CPU, RAM, or storage with other users**.

For this kind of setup, plan for at least 8 CPU cores, 16 to 32 GB RAM, and fast SSD or NVMe storage. Ideally, you’ll also use an Intel or NVIDIA GPU for hardware transcoding.

### Which operating system should you use Debian or Ubuntu?

Both [Linux server distributions](https://www.ionos.com/digitalguide/server/configuration/linux-server-distributions/) work well with Jellyfin. That said, Ubuntu Server 24.04 LTS is usually the easier choice if you’re just getting started. Docker officially supports [Ubuntu](https://www.ionos.com/digitalguide/server/know-how/ubuntu-the-linux-system-for-everyone/) 24.04, and most guides are based on it. Although [Debian](https://www.ionos.com/digitalguide/server/know-how/debian-the-universal-system-software/) is also very stable, Ubuntu tends to be a bit more beginner-friendly and helps you avoid some common setup issues.

Tip If your media collection is growing quickly, external storage can be helpful. For beginners, local [SSD](https://www.ionos.com/digitalguide/server/know-how/what-is-ssd/) or NVMe storage is the easiest option. You can also use external storage such as [object storage](https://www.ionos.com/digitalguide/server/know-how/what-is-object-storage/), but you’ll first need to mount it as a file system first, using a mount tool. This is because Jellyfin reads files directly from the file system and doesn’t support object storage as a native source. A good workaround is to use object storage as an archive for older media you don’t need all the time.

## How to install a Jellyfin server on Ubuntu using Docker

In this example, we’ll walk you through how to install Jellyfin on Ubuntu Server 24.04 LTS using Docker Engine and the [Docker Compose](https://www.ionos.com/digitalguide/server/configuration/docker-compose-tutorial/) plugin. This approach is especially beginner-friendly because Docker keeps everything nicely separated and makes updates easier to manage.

### Step 1: Update your Ubuntu server

Connect to your server via [SSH](https://www.ionos.com/digitalguide/server/tools/ssh-secure-shell/) and update your system:

```bash
sudo apt update 
sudo apt upgrade -y
```

If needed, restart the server (you will have to log in again after rebooting):

```bash
sudo reboot
```

This step makes sure you’re starting with up-to-date packages, the latest security updates and a clean system. If you’re working with a freshly set up Ubuntu server, this is a good first thing to do.

### Step 2: Install Docker on Ubuntu 24.04

Next, install Docker using the official APT [repository](https://www.ionos.com/digitalguide/server/know-how/repository/). First, remove any older or potentially conflicting packages:

```bash
sudo apt remove docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc -y
```

Then set up the official Docker repository:

```bash
sudo apt update 
sudo apt install ca-certificates curl -y 
sudo install -m 0755 -d /etc/apt/keyrings 
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc 
sudo chmod a+r /etc/apt/keyrings/docker.asc 
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF 
Types: deb 
URIs: https://download.docker.com/linux/ubuntu 
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") 
Components: stable 
Signed-By: /etc/apt/keyrings/docker.asc 
EOF 
sudo apt update
```

Now install Docker Engine, Buildx, and the Compose plugin using:

```bash
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
```

Then, check Docker is running:

```bash
sudo systemctl status docker
```

You should see `active (running)`:

[![Image: Docker status display](https://www.ionos.com/digitalguide/fileadmin/_processed_/b/9/csm_jellyfin-docker-active_ed36b0ce76.webp "Docker status display")](https://www.ionos.com/digitalguide/fileadmin/DigitalGuide/Screenshots_2026/jellyfin-docker-active.jpg) The “active” status confirms Docker is running. Run a quick test to make sure everything works:

```bash
sudo docker run hello-world
```

The output should look like this:

[![Image: Docker Hello World](https://www.ionos.com/digitalguide/fileadmin/_processed_/2/a/csm_jellyfin-docker-hello-world_0a0da78b63.webp "Docker Hello World")](https://www.ionos.com/digitalguide/fileadmin/DigitalGuide/Screenshots_2026/jellyfin-docker-hello-world.jpg) The Hello World message tells you Docker is installed and working as expected. ### Step 3: Use Docker without sudo

By default, Docker commands require `sudo`. If you prefer, you can add your user to the `docker` group:

```bash
sudo usermod -aG docker $USER 
newgrp docker
```

Note The Docker documentation points out that anyone in the docker group effectively has root-level access. That’s fairly normal on a personal server, but it’s still something to keep in mind. If other users also have access to your server, this can quickly turn into a security issue.

### Step 4: Create the folder structure

Now everything’s set up, let’s create the folder structure for your Jellyfin server. To keep things organized, it helps to separate your configuration, [cache](https://www.ionos.com/digitalguide/hosting/technical-matters/what-is-a-cache/) and media files. Go ahead and create the following folders on your host system (you can structure them differently if you prefer):

```bash
mkdir -p ~/jellyfin/config 
mkdir -p ~/jellyfin/cache 
mkdir -p ~/media/movies 
mkdir -p ~/media/tvshows 
mkdir -p ~/media/music 
mkdir -p ~/media/photos
```

`config` is where Jellyfin stores its configuration, users and database. `cache` is used for temporary data. The media files themselves are stored in separate folders.

### Step 5: Determine the user’s UID and GID

Jellyfin can run inside the container using the user and group ID of your Linux user. This makes it easier to handle file permissions. To get both values, run:

```bash
id
```

You’ll see a set of numbers in the output: the UID and GID values. Make a note of them. You’ll need them in the next step for the Compose file.

### Step 6: Create the Docker Compose file for Jellyfin

Go to your working directory and create a file called `docker-compose.yml`. In this example, we’ll use the nano editor, but you can create the file however you like.

```bash
mkdir -p ~/jellyfin 
cd ~/jellyfin 
nano docker-compose.yml
```

Now paste the following content into the file:

```yaml
services: 
    jellyfin: 
        image: jellyfin/jellyfin 
        container_name: jellyfin 
        user: "1000:1000" 
        ports: 
            - "8096:8096/tcp" 
            - "7359:7359/udp" 
        volumes: 
            - ./config:/config 
            - ./cache:/cache 
            - type: bind 
                source: /home/YOURUSERNAME/media/movies 
                target: /media/movies 
                read_only: true 
            - type: bind 
                source: /home/YOURUSERNAME/media/tvshows 
                target: /media/tvsshows
                read_only: true 
            - type: bind 
                source: /home/YOURUSERNAME/media/music 
                target: /media/music 
                read_only: true 
            - type: bind 
                source: /home/YOURUSERNAME/media/photos 
                target: /media/photos 
                read_only: true 
        environment: 
            - JELLYFIN_PublishedServerUrl=http://YOUR-SERVER-IP:8096 
        restart: unless-stopped
```

Then, update the following values in the file:

- replace `1000:1000` with your actual UID:GID from the previous step
- `YOURUSERNAME` with your Linux username
- `YOUR-SERVER-IP` with your server’s [IP address](https://www.ionos.com/digitalguide/server/know-how/what-is-an-ip-address/)

Tip The media folders are mounted as `read_only: true`. This means Jellyfin server can read your files, but it can’t change them. For a personal media server, that’s both safer and more practical.

### Step 7: Start the Jellyfin container

Now you can start the container you just created using Docker Compose. It will run in the background:

```bash
sudo docker compose up -d
```

Then check if the container is up and running:

```bash
sudo docker compose ps
```

[![Image: Display after Docker compose](https://www.ionos.com/digitalguide/fileadmin/_processed_/f/4/csm_jellyfin-docker-compose_555ea97a3a.webp "Display after Docker compose")](https://www.ionos.com/digitalguide/fileadmin/DigitalGuide/Screenshots_2026/jellyfin-docker-compose.jpg) The terminal output shows that the Jellyfin container is up and running. ### Step 8: Open Jellyfin in your browser

Now open your server’s address in your browser using the default Jellyfin port:

```none
http://SERVER-IP:8096
```

The setup wizard will start automatically in your browser.

Note If you’re using an IONOS server, you’ll first need to configure the [firewall](https://www.ionos.com/digitalguide/server/security/what-is-a-firewall/) in the Cloud Panel to allow [TCP](https://www.ionos.com/digitalguide/server/know-how/introduction-to-tcp/) connections on port 8096.

### Step 9: Set up Jellyfin using the wizard

Jellyfin will guide you through the **basic setup** in your browser. Start by choosing your language, then create an admin account with a secure password. After that, set up your libraries. For example, select “Movies,” “TV shows,” “Music,” and “Photos” and point Jellyfish to the folders you mounted in the container, such as `/media/movies` or `/media/tvshows`, as in our example. Once that’s done, Jellyfin will automatically pull in metadata, cover art and additional data, as long as your server has an internet connection.

[![Image: Screenshot of Jellyfin in the browser](https://www.ionos.com/digitalguide/fileadmin/_processed_/5/6/csm_jellyfin-server-setup_dd8c16e054.webp "Screenshot of Jellyfin in the browser")](https://www.ionos.com/digitalguide/fileadmin/DigitalGuide/Screenshots_2026/jellyfin-server-setup.jpg) When you open Jellyfin in your browser, the setup wizard walks you through everything step by step. ### Step 10: Keep your media organized

For Jellyfin to recognize your files correctly, your media should be clearly named and well organized. For movies, it helps to store each title in its own folder. For TV shows, organize them by season. Music works best when your tags are clean and consistent. The more structured your folders are, the less manual work you’ll have later when it comes to metadata and matching. It’s not something you have to do, but it definitely makes things easier later on.

Keep the following **security tips for your Jellyfin server** in mind:

- **Use HTTPS**: If you want to access Jellyfin over the Internet, make sure to secure it with HTTPS. The easiest way to do this is with a reverse proxy and a free TLS certificate.
- **Avoid direct internet exposure**: Try not to open the Jellyfin port directly on your router. Instead, use a reverse proxy or a [VPN](https://www.ionos.com/digitalguide/server/know-how/what-is-a-vpn-virtual-private-network/).
- **Use strong passwords**: Set a [secure password](https://www.ionos.com/digitalguide/server/security/protect-sensitive-data-with-a-strong-password/) for the admin account and create separate user accounts for others.
- **Keep your system up to date**: Regularly update your Ubuntu system, Docker, and the Jellyfin image.
- **Mount media folders as read-only**: If you’re running Jellyfin in Docker, it’s a good idea to mount your media folders as read-only (`read_only`) to avoid accidental changes to your files.

## How to connect Jellyfin to a domain

If you want to access Jellyfin through a domain like `jellyfin.yourdomain.com`, you’ll need three things:

- A [domain](https://www.ionos.com/digitalguide/domains/domain-tips/what-is-a-domain/) or subdomain
- A [DNS](https://www.ionos.com/digitalguide/server/know-how/domain-name-system/) record that points to your server’s public IP address
- A reverse proxy with HTTPS. Jellyfin specifically recommends Caddy

### Step 1: Set the DNS record for the subdomain

Create an [A record](https://www.ionos.com/digitalguide/hosting/technical-matters/a-record/) with your domain provider, for example:

```none
jellyfin.yourdomain.com -> YOUR-PUBLIC-IP
```

If you’re using IPv6, you’ll also need to create an AAAA record. For automatic HTTPS with Caddy, the DNS record must already point to your server correctly.

Note For your Jellyfin server to be accessible over HTTPS later on, ports **80 (HTTP)** and **443 (HTTPS)** need to be open on your server or in your firewall. The reverse proxy uses these ports to handle incoming requests and issue TLS certificates.

### Step 2: Install Caddy

Jellyfin recommends Caddy because it makes setting up HTTPS really straightforward. To install Caddy on Ubuntu, use the official package method and run the following commands:

```bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl 
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg 
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list 
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg 
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list 
sudo apt update 
sudo apt install caddy -y
```

Once the installation is complete, Caddy starts automatically as a system service.

### Step 3: Configure Caddy

Next, update the Caddy configuration. We’ll use nano again here, but any text editor will work as well:

```bash
sudo nano /etc/caddy/Caddyfile
```

Add the following:

```none
jellyfin.yourdomain.com { 
reverse_proxy 127.0.0.1:8096 
}
```

Save the file, then check the configuration:

```bash
sudo caddy validate --config /etc/caddy/Caddyfile
```

If everything looks good, reload Caddy:

```bash
sudo systemctl reload caddy
```

### Step 4: Bind Jellyfin locally to Caddy only

Once your domain is working, you should update your Compose file so the Jellyfin **no longer listens publicly on port 8096**. To do this, open `~/jellyfin/docker-compose.yml` again and replace the port section with:

```yaml
ports: 
    - "127.0.0.1:8096:8096/tcp" 
    - "7359:7359/udp"
```

Then restart the container:

```bash
sudo docker compose up -d
```

Jellyfin will now only be accessible locally, while Caddy handles the secure public connection. Finally, add the proxy as a **Known Proxy** in Jellyfin’s network settings. This allows Jellyfin to correctly process the headers set by the proxy. You’ll find this option in the web interface under **Dashboard** → **Networking** → **Known Proxies**.


This is a markdown version of: [https://www.ionos.com/digitalguide/server/configuration/jellyfin-server/](https://www.ionos.com/digitalguide/server/configuration/jellyfin-server/) for AI/LLM consumption.