# How to Self-Host Jellyfin With Docker or One Click (2026)

> Jellyfin Docker setup, step by step: server size, a Compose file with NGINX and SSL, the one-click way on xCloud, and backups and updates after install.

**Jellyfin Docker** is the most common way to self-host Jellyfin: you run the official `jellyfin/jellyfin` container with three folders for config, cache and media, then put a reverse proxy with HTTPS in front. You can write that setup yourself on any Ubuntu server, or let xCloud's one-click app run the same container for you.

The container itself starts in seconds. The work is everything around it: a domain, a certificate, WebSockets through the proxy, a place to put your media, and a backup you have actually restored.

This guide covers both paths. First the **Docker Compose** way, step by step, then the one-click way on xCloud, with what each one leaves on your plate. If you are still deciding whether Jellyfin fits you, start with [**what Jellyfin is and what it does**](/what-is-jellyfin-key-features-and-use-cases/).

![Who does each job when you self-host Jellyfin: Docker Compose on your own vs one-click on xCloud](/_landing/blog/self-host-jellyfin-image-1.png)

## TL;DR

- **Jellyfin** is a free, GPL-2.0 media server for your own movies, TV, music and photos, with no paid tier.
- **Server size:** Jellyfin recommends 8 GB of RAM for an average setup and says 4 GB may be enough on a Linux server without a desktop. CPU transcoding is the real limit.
- **Manual path:** Docker Compose with the official image, NGINX in front and a free Let's Encrypt certificate. Visitors reach Jellyfin only through your domain over HTTPS, not by server IP and port.
- **One-click path:** pick **Jellyfin** in xCloud's [**One Click Apps**](/one-click-apps/), choose a domain and a server, and xCloud runs Jellyfin 10.11.11 behind HTTPS.
- **Either way, you still own** the admin account, your media, upgrades and backups of the config volume.
- **Not in the one-click template:** GPU transcoding, DLNA and local network discovery.

## What xCloud's One-Click Jellyfin Actually Runs

We read xCloud's own Jellyfin template (its Compose file and manifest). Here is exactly what the template installs, as of November 2026:

| Part | What the template sets up |
|---|---|
| **Image** | `jellyfin/jellyfin:10.11.11`, locked to one exact build (pinned by image digest), so it never changes on its own |
| **Port** | Container port **8096**, only reachable through your domain over HTTPS, not by server IP and port |
| **Volumes** | `jellyfin_config` at `/config`, `jellyfin_cache` at `/cache`, `jellyfin_media` at `/media` |
| **Server URL** | `JELLYFIN_PublishedServerUrl` set to `https://<your-domain>` |
| **Health check** | Checks `/health` inside the container every 15 seconds; the container restarts automatically (`restart: always`) |
| **Minimum server** | 2 GB RAM, 2 CPU cores, 20 GB disk, on an NGINX server with Docker |
| **Install form** | No app fields and no default password; you create the first admin in Jellyfin's setup wizard |
| **Left out on purpose** | Host networking, UDP discovery (7359), DLNA, privileged mode and GPU passthrough |

![What xCloud's one-click Jellyfin runs: NGINX with HTTPS, the Jellyfin container on port 8096 and three named volumes](/_landing/blog/self-host-jellyfin-image-2.png)

Two lines matter later. Because the version is locked, updates are a manual step, which we cover in the [after-install section](#after-install-updates-backups-and-security). The missing GPU passthrough is why the server size matters more than on a home box with a graphics chip.

## What You Need to Self-Host Jellyfin

Jellyfin's [**hardware selection guide**](https://jellyfin.org/docs/general/administration/hardware-selection/) is the source for the table below. We checked it on 6 November 2026.

| Item | What Jellyfin recommends |
|---|---|
| **RAM** | At least 8 GB for the average setup; 4 GB may be enough on Linux without a desktop |
| **CPU** | Any modern 4-thread CPU, assuming hardware acceleration is set up; servers without a GPU are not recommended for transcoding |
| **System disk** | A 100 GB SSD for the OS, Jellyfin files and the transcoding cache |
| **Media disk** | Anything that reads faster than your media's bitrate; avoid SMR hard drives |
| **Upload bandwidth** | At least 20 Mbps for remote access |
| **Ports** | 8096 for the web app and API; 80 and 443 open for your reverse proxy |

The honest reading: a cloud server without a GPU is a **direct play** server first. Direct play means the app on your TV or phone plays the original file, so the server just sends bytes. When a device cannot play the file, Jellyfin transcodes on the CPU, and the hardware guide says plainly that this is very demanding.

Rule of thumb: start with 4 to 6 GB of RAM and a few CPU cores for one household that mostly direct plays. Plan your disk around the library, not the 20 GB minimum.

## Option 1: Self-Host Jellyfin With Docker Compose

This path follows Jellyfin's [**official container install page**](https://jellyfin.org/docs/general/installation/container/) on a fresh Ubuntu server. Check each step against that page for the Jellyfin version you install.

We built the Compose file and NGINX block below from Jellyfin's official examples and did not run them on a test server. Test them on your server before you rely on them.

### Step 1: Prepare the server and domain

Point an A record for your domain (for example `media.example.com`) at `SERVER_IP`. Install Docker using its official instructions for Ubuntu. Open only ports 22, 80 and 443 in your firewall; our [**VPS security guide**](/maximize-your-vps-security/) covers SSH keys and firewall basics.

Create the folders Jellyfin will use:

```bash
sudo mkdir -p /opt/jellyfin/config /opt/jellyfin/cache /srv/media/movies /srv/media/shows
```

### Step 2: Write the Compose file

Create `/opt/jellyfin/docker-compose.yml`. It is based on Jellyfin's official example, with these changes:

- A fixed version tag (`10.11.11`) instead of the untagged image, which tracks the latest release.
- The web port bound to `127.0.0.1` so only NGINX can reach it.
- No `7359/udp` discovery port, which only helps on a home network.
- `JELLYFIN_PublishedServerUrl` set to your HTTPS domain.
- One media folder, mounted read-only, instead of the example's separate media folders.
- The optional `user`, `extra_hosts` and custom fonts lines left out.

```yaml
services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.11
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "127.0.0.1:8096:8096"
    environment:
      - JELLYFIN_PublishedServerUrl=https://media.example.com
    volumes:
      - /opt/jellyfin/config:/config
      - /opt/jellyfin/cache:/cache
      - type: bind
        source: /srv/media
        target: /media
        read_only: true
```

Jellyfin's own example uses `read_only: true` on one of its media folders, and we apply it to the whole library here: Jellyfin can read your library but cannot change or delete it. The `10.11.11` tag matches xCloud's template; check Jellyfin's GitHub releases page and pick the version you want to run.

Start it with `docker compose up -d` from `/opt/jellyfin`, then watch `docker compose logs -f` until Jellyfin reports it has started.

### Step 3: Put NGINX and SSL in front

Install NGINX and Certbot, then create `/etc/nginx/sites-available/jellyfin`. This is a trimmed version of Jellyfin's own NGINX guide. The `/socket` block matters: Jellyfin uses **WebSockets**, and without the upgrade headers the web app loses live updates.

```nginx
server {
    listen 80;
    server_name media.example.com;
    client_max_body_size 20M;

    location / {
        proxy_pass http://127.0.0.1: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;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_buffering off;
    }

    location /socket {
        proxy_pass http://127.0.0.1:8096;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

Link it into `sites-enabled`, run `sudo nginx -t`, reload NGINX, then run `sudo certbot --nginx -d media.example.com`. Certbot switches the block to HTTPS and sets up renewal, which needs the port 80 listener to stay.

### Step 4: Run the setup wizard and add a library

Open `https://media.example.com`, pick a language and create the first administrator with a unique password. Add a library that points to `/media/movies` (the container path, not `/srv/media/movies`), finish the wizard and play a test file.

Last, tell Jellyfin to trust NGINX. Go to **Dashboard → Networking**, add the proxy address under **Known Proxies** and save. Jellyfin's reverse proxy page explains that without this, it ignores forwarded headers and logs every viewer with the proxy's address.

## Option 2: One-Click Jellyfin on xCloud

The one-click path gives you the stack from the first table without writing any of it. The general walkthrough is 👉 [**how to use One-Click App templates in xCloud**](/docs/how-to-use-one-click-app-templates-in-xcloud/).

### Step 1: Pick Jellyfin in the catalog

Go to **Sites → New Site**, select **One-Click Apps** and search for **Jellyfin**. The setup page shows **Runs on Nginx, Docker** and the minimums: 2 GB RAM, 2 CPU cores and 20 GB of disk.

### Step 2: Choose a server

Pick an NGINX server with enough resources, or create one. If Docker is not installed yet, xCloud installs it as part of the site setup the first time a container app needs it, as described in [**enabling Docker on an NGINX server**](/docs/enable-docker-on-an-nginx-server-in-xcloud/). OpenLiteSpeed servers cannot run Docker apps.

If the server is too small, the card shows what Jellyfin needs and a link such as **Get a larger server**. Whether you can resize the current server instead depends on the server and on your role in the team; without permission, you see **Ask a team administrator to resize this server.**

### Step 3: Choose Demo Site or Go Live

Choose **Demo Site** to test on a temporary xCloud address, or **Go Live** to use your own domain. Jellyfin's template has no other fields, so click **Create** and wait for the deployment tasks in **Recent Events** to finish.

### Step 4: Create the admin and add media

Open the URL shown on the app overview and run Jellyfin's setup wizard to create the first administrator. There is no default password, so nobody else can claim the server.

Media goes into the `jellyfin_media` volume, mounted at `/media`. That folder is owned by root, so copy files in with a sudo user (or `docker cp`); a normal site-user SFTP upload will not land there. Then add a library such as `/media/movies` in **Dashboard → Libraries**.

## After Install: Updates, Backups and Security

These three jobs are the same on both paths, and they decide whether your server still works next year.

### Updates

Jellyfin's [**backup and restore page**](https://jellyfin.org/docs/general/administration/backup-and-restore/) has the line to remember: Jellyfin has **no downgrade mechanism**. Once a newer version starts and migrates the database, only a backup takes you back.

On a manual install, back up first, change the tag in `docker-compose.yml`, then run `docker compose pull` and `docker compose up -d`. On xCloud, **App Actions → Update** pulls the images named in the app's Compose file. Because the template locks Jellyfin to one exact 10.11.11 build, Update pulls that same version again. To move up, take a backup and change the image line on the **Compose** page, as described in 👉 [**how to update a One-Click App and edit its Docker Compose**](/docs/update-a-one-click-app-and-edit-its-docker-compose-in-xcloud/). Keep the volume names exactly as they are.

### Backups

The volume to protect is **config**: users, libraries, watch history, metadata, plugins and the database all live there. Media is the big one by size; cache is rebuilt on its own, though keeping it shortens recovery.

On a manual install, Jellyfin's guide says to stop the server before copying the config folder (`docker stop jellyfin`), because the database is locked while it runs. Jellyfin 10.11 and later also has a built-in backup in the dashboard that runs while the server is online.

On xCloud, open the site and go to **Backup → Previous Backups** for **Backup Now**, or schedule backups in **Backup → Backup Settings**. Docker app backups capture named volumes, the Compose file and the `.env` file. 👉 See [**how to back up and restore Docker apps**](/docs/backup-and-restore-docker-apps/). Keep irreplaceable media somewhere else too.

### Security

Jellyfin's [**hardware selection guide**](https://jellyfin.org/docs/general/administration/hardware-selection/#networking) says the server is not designed to be exposed directly to the internet, which is why both paths keep Jellyfin reachable only through NGINX on your domain. Use a long admin password, give each family member their own account instead of sharing the admin, and remove accounts you no longer need.

For a family-only server, you can add an outer password prompt with **Tools → Basic Authentication** on xCloud. Test it with your TV and phone apps before you rely on it.

## What the One-Click Template Does Not Do

Here is the honest list, read from the same template:

- **No GPU transcoding.** Hardware acceleration needs host device access, so it is not enabled. Direct play and CPU transcoding work.
- **No DLNA or local network discovery.** Point every app at your HTTPS URL; nothing will find the server on its own.
- **No automatic Jellyfin upgrades.** The image is pinned, so you choose when to move up.
- **No media included and no downloader.** You bring your own files, and you are responsible for using them lawfully.
- **It needs an NGINX server.** OpenLiteSpeed servers cannot run Docker apps.

To undo the install, delete the site from xCloud. Take a backup first if you want to keep your users and library settings.

## Docker Compose vs One-Click: Which to Choose

Jellyfin itself is free either way. What differs is how much of the plumbing you own.

| | Docker Compose on your own | One-click on xCloud |
|---|---|---|
| **Jellyfin cost** | Free (GPL-2.0) | Free (GPL-2.0) |
| **Setup work** | Docker, Compose file, NGINX, Certbot, firewall | Catalog, server, domain |
| **HTTPS and WebSockets** | You write and renew it | Set up for you |
| **GPU transcoding** | Possible if your server has a supported GPU | Not enabled |
| **Local network discovery and DLNA** | Possible on a home network | Not enabled |
| **Backups** | You script them | Scheduled Docker app backups |
| **Upgrades** | You change the tag | You change the image on the Compose page |
| **Server security updates** | You | [**Automatic Ubuntu security updates**](/docs/how-automated-security-updates-and-auto-reboot-work-in-xcloud/) |

**Choose Docker Compose if** Jellyfin runs on a home box with a graphics chip, you want DLNA for older TVs, or you enjoy owning every layer.

**Choose one-click if** you want a cloud server the household can reach from anywhere over HTTPS, mostly direct play, and backups you can schedule from a dashboard. Our guide to [**self-managed vs managed hosting**](/self-managed-vs-managed-hosting/) goes deeper on that trade-off.

## Get Your Own Media Server Running This Week

If you like owning every layer, the Compose file above is a solid start: pin the version, keep Jellyfin behind NGINX, pass WebSockets through NGINX, set Known Proxies and test a restore before you invite the family.

If you would rather skip the plumbing, deploy from [**xCloud Jellyfin hosting**](/jellyfin-hosting/) and spend that hour sorting your library instead. Compare server sizes on the [**pricing page**](/pricing/) or browse other container apps on [**Docker hosting**](/docker-hosting/). Companion apps such as [**Jellystat**](/jellystat-hosting/) for playback statistics and [**Fladder**](/fladder-hosting/) as another web client come from the same catalog, and [**Navidrome**](/navidrome-hosting/) suits a music-only library. For another app set up the same way, see our guide to [**self-hosting Nextcloud**](/self-host-nextcloud/).

If you have found this blog helpful, feel free to [**subscribe to our blogs**](https://xcloud.host/blog/) for valuable tutorials, guides, knowledge, and tips on web hosting and server management. You can also join our [**Facebook community**](https://www.facebook.com/groups/xcloud.community) to share insights and engage in discussions.

## Frequently Asked Questions

### Is Docker the best way to run Jellyfin?

For a Linux server, it is the most common way. Jellyfin publishes its own jellyfin/jellyfin image and documents Docker Compose on its container install page. Docker keeps Jellyfin's config, cache and media in separate volumes, which makes backups and moves simpler.

### How much RAM does a Jellyfin Docker server need?

Jellyfin's hardware guide recommends 8 GB for the average setup and says 4 GB may be enough for a Linux server without a desktop. xCloud's template asks for at least 2 GB, 2 CPU cores and 20 GB of disk, which suits setup and light direct play only.

### Which ports does Jellyfin use in Docker?

Port 8096 serves the web interface and API. Jellyfin's official example also maps 7359/udp for client auto discovery on a local network. On a public server you only need 8096 behind a reverse proxy on ports 80 and 443.

### Can Jellyfin on xCloud use a GPU for transcoding?

No. The xCloud template does not enable hardware acceleration, because that needs host device access and drivers. Direct play and CPU transcoding work, so pick a larger server if several people will watch transcoded video at once.

### Does xCloud update Jellyfin for me?

No. The template locks Jellyfin to one exact 10.11.11 build, so App Actions, Update pulls that same version again. To move to a newer release, take a backup, edit the image line on the Compose page and check playback afterwards.

### How do I add movies to Jellyfin on xCloud?

Copy files into the jellyfin_media volume, which is mounted at /media in the container, then add a folder such as /media/movies in Dashboard, Libraries. The folder is owned by root, so you need a sudo user; normal site-user SFTP uploads will not land there.
