# How to self-host Jellyfin with Docker Compose

> Set up the Jellyfin media server with Docker Compose: media folders, permissions, hardware transcoding, HTTPS reverse proxy, backups and safe upgrades.

## Key facts

| Fact | Value |
|---|---|
| App | Jellyfin (https://appsgit.com/apps/jellyfin) |
| Difficulty | beginner |
| Time | about 20 minutes |
| Requirements | 2 vCPU / 2 GB RAM (more for software transcoding); Docker + Docker Compose v2; Your movies, shows or music on local or NAS storage; A domain name (optional, for remote access) |
| Last updated | 2026-10-06 |

## What is Jellyfin?

Jellyfin is a free media server that organises your movies, TV shows, music and photos and streams them to browsers, phones, TVs and set-top boxes. It is open source under the GPL-2.0 license, community-run, and has no premium tier, tracking or required online account. It is a common replacement for Plex and Emby.

## Requirements

- A Linux server with 2 CPU cores and 2 GB of RAM. Software transcoding of 4K content needs a much stronger CPU, or a GPU.
- Docker Engine and Docker Compose v2.
- Your media library on a local disk or a mounted NAS share.
- Optional: an Intel CPU with Quick Sync, an AMD GPU or an NVIDIA GPU for hardware transcoding.

## Step 1: Prepare the server

This guide uses Ubuntu 24.04 with Docker installed. If you still need Docker, follow the [official Docker install guide](https://docs.docker.com/engine/install/ubuntu/). Create folders for config and cache:

```bash
mkdir -p ~/jellyfin/{config,cache} && cd ~/jellyfin
id -u && id -g
```

Note the two numbers printed by `id`. Jellyfin will run as that user, so it needs read access to your media folders.

## Step 2: Create the Docker Compose file

Save this as `docker-compose.yml`, adjusting the media paths and the `user` line:

```yaml
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: "1000:1000"
    restart: unless-stopped
    ports:
      - "8096:8096"
      - "7359:7359/udp"
    environment:
      JELLYFIN_PublishedServerUrl: "https://media.example.com"
      TZ: "Europe/London"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /srv/media/movies:/media/movies:ro
      - /srv/media/shows:/media/shows:ro
      - /srv/media/music:/media/music:ro
    # Uncomment for Intel Quick Sync or AMD VAAPI hardware transcoding:
    # devices:
    #   - /dev/dri:/dev/dri
    # group_add:
    #   - "993"
```

Mounting media read-only (`:ro`) protects your files from accidental changes. Jellyfin does not need write access unless you want it to save artwork and NFO files next to your media. For hardware transcoding with `/dev/dri`, replace `993` with the group ID of the `render` group (`getent group render | cut -d: -f3`). Jellyfin does not use any secrets in the Compose file. You create the admin password in the setup wizard.

`latest` tracks the current stable release. To pin a version, use a tag from [Docker Hub](https://hub.docker.com/r/jellyfin/jellyfin/tags), such as the major version tag.

## Step 3: Start and open the app

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

Open `http://YOUR_SERVER_IP:8096`. The setup wizard asks for a display language, then creates the administrator account. Use a strong password, because this account can also manage the server. Next, add libraries: choose a content type (Movies, Shows, Music) and point it at the matching path inside the container, for example `/media/movies`. Jellyfin scans the folders and fetches metadata and artwork.

Name files the way Jellyfin expects (`Movie Name (2024)/Movie Name (2024).mkv` and `Show Name/Season 01/Show Name S01E01.mkv`) for accurate matching.

## Step 4: Put it behind HTTPS

For remote access, use a reverse proxy instead of exposing port 8096. With [Caddy](https://caddyserver.com/docs/):

```caddyfile
media.example.com {
    reverse_proxy 127.0.0.1:8096
}
```

Then, in Dashboard, Networking, add the proxy's IP to "Known proxies" so Jellyfin logs real client addresses and applies its LAN and remote bitrate rules correctly. Nginx Proxy Manager works too. Enable "Websockets Support" on the proxy host. When remote access works, change the mapping to `"127.0.0.1:8096:8096"` if you do not need direct LAN access on 8096.

## Backups and upgrades

Back up the `config` folder. It holds the database, users, watch history, plugins and settings. The `cache` folder can be rebuilt and does not need a backup. Stop the container before copying `config` so the SQLite database is consistent:

```bash
docker compose stop && tar czf jellyfin-config-$(date +%F).tgz config && docker compose start
```

Upgrade with:

```bash
docker compose pull && docker compose up -d
```

Jellyfin migrates its database on major upgrades and cannot be downgraded afterwards, so take a config backup first.

## Troubleshooting

- **Libraries are empty after a scan:** the container user cannot read the media path, or the library points at a host path instead of the container path (`/media/...`).
- **Playback buffers or the CPU is pegged:** the client is transcoding. Enable hardware acceleration in Dashboard, Playback, or use a client that can direct-play the format.
- **Hardware transcoding fails:** check that `/dev/dri` exists on the host and that the `group_add` ID matches the `render` group.
- **Apps cannot auto-discover the server:** UDP 7359 must be published, and discovery does not work across subnets or VPNs.

## Next steps

Install the Jellyfin apps for your TV and phone, set per-user parental controls, and add plugins such as OpenSubtitles from the built-in catalog. Community repositories add extras like Intro Skipper.

## FAQ

### What port does Jellyfin use?

Jellyfin serves its web UI and API on port 8096 over HTTP. Port 8920 is the optional built-in HTTPS port, and UDP 7359 is used for client auto-discovery on the local network.

### Is Jellyfin free?

Yes. Jellyfin is completely free and open source under the GPL-2.0 license. There is no premium tier, account requirement or paywalled feature such as hardware transcoding.

### Jellyfin vs Plex: which is better?

Jellyfin gives you every feature, including hardware transcoding and live TV, for free and without a cloud account. Plex has more polished apps on some smart TVs and easier remote access, but key features require Plex Pass.

### Does Jellyfin need a GPU?

No, but a GPU or an Intel CPU with Quick Sync makes transcoding far cheaper. Without one, clients that cannot direct-play a file will push CPU usage high.

### Why can Jellyfin not see my media files?

Usually the container user has no read permission on the mounted folder. Make sure the user in the Compose file can read the media directory on the host.

Prefer not to do it yourself? [appsgit installation help](https://appsgit.com/services/install) installs it on your server for a fixed quote.

---

Canonical page: https://appsgit.com/guides/jellyfin
Source: appsgit (https://appsgit.com), the app store for github. Data from the GitHub API, refreshed nightly.
Machine access: JSON API https://appsgit.com/api/v1/apps (OpenAPI: https://appsgit.com/openapi.json), MCP server https://mcp.appsgit.com/mcp, full index https://appsgit.com/llms-full.txt.
