# Install & Configure Jellyfin

> Install Jellyfin inside the Debian LXC, connect it to your media libraries, and integrate it with Sonarr, Radarr, and Seerr.

# Install & Configure Jellyfin

This page covers Jellyfin. If you chose Plex instead, see [Install & Configure Plex](/docs/home-server/media-automation/installation/install-plex).

With the Jellyfin LXC running and storage mounted, install Jellyfin and connect it to your libraries.

## Install Jellyfin on Debian

Open a shell inside the Jellyfin LXC and run:

```bash
apt update && apt upgrade -y
apt install -y curl

# Official Jellyfin install script: adds the repository and installs the package
curl https://repo.jellyfin.org/install-debuntu.sh | bash
```

The script detects your Debian version, adds the Jellyfin apt repository, and installs the package. Jellyfin starts automatically after installation.

Verify it is running:

```bash
systemctl status jellyfin
```

## Open the web UI

From a browser on your LAN:

```
http://<jellyfin-lxc-ip>:8096
```

The setup wizard will guide you through initial configuration. Create an admin account; no external account is required.

## Add media libraries

In the Jellyfin setup wizard (or later via **Administration → Dashboard → Libraries**), add:

| Library type | Path |
|-------------|------|
| Movies | `/mnt/media/movies` |
| TV Shows | `/mnt/media/tv` |

These paths match what was mounted in the [Mount Storage](/docs/home-server/media-automation/installation/mount-storage) step.

Jellyfin will scan on startup. The directories will be empty until Sonarr and Radarr download something.

## Automatic library updates

Jellyfin applies automatic scanning settings to **each individual library**, not globally. To make Jellyfin detect new files immediately after Sonarr or Radarr imports them, enable real-time monitoring on each library:

1. Open the Jellyfin Web Client, click the hamburger menu, and select **Dashboard**
2. On the left sidebar under the "Server" section, click **Libraries**
3. Locate the library you want to update (e.g., *Movies* or *TV Shows*), click the **three dots (...)** on its card, and select **Manage Library**
4. Scroll down near the bottom of the settings popup and check **Enable real-time monitoring**, then click **Save**

Repeat for both your Movies and TV Shows libraries. Jellyfin will now pick up new files the moment they appear on disk, with no scheduled scan delay.

**Note: real-time monitoring relies on inotify and does not work over NFS.** If your arr stack and Jellyfin run on separate machines connected by NFS, the filesystem event never reaches Jellyfin and real-time monitoring will not fire.

In that case, use the Sonarr/Radarr built-in Jellyfin connection instead:

1. In Sonarr or Radarr, go to **Settings → Connect** and add a **Jellyfin** connection
2. Enter the Jellyfin server URL and API key
3. Enable **On Import** and **On Upgrade**

Sonarr/Radarr will notify Jellyfin via API after each import, which works regardless of how Jellyfin accesses the files.

## Connect Seerr to Jellyfin

Seerr supports Jellyfin natively. If you are setting up Seerr for the first time, choose Jellyfin during the setup wizard. If Seerr is already running with Plex, you can add Jellyfin as an additional media server.

1. In Jellyfin, go to **Administration → Dashboard → API Keys** and create a key for Seerr
2. In the Seerr setup wizard, select **Jellyfin** as your media server
3. Enter the server URL (`http://<jellyfin-lxc-ip>:8096`) and the API key
4. Click **Sync Library** to confirm the connection

Users authenticate with Jellyfin accounts you create under **Administration → Users**. No plex.tv account is needed.

## GPU passthrough (hardware transcoding)

Hardware transcoding is free in Jellyfin; no paid tier is required. To enable it, pass through the GPU from the Proxmox host to the Jellyfin LXC.

**For Intel iGPU (QSV):**

On the Proxmox host, add the following lines to the LXC config file (`/etc/pve/lxc/<id>.conf`):

```
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
lxc.hook.pre-start: sh -c "chown 100000:100154 /dev/dri/renderD128"
```

Inside the Jellyfin LXC, add the `jellyfin` user to the render group:

```bash
usermod -aG render jellyfin
apt install -y intel-opencl-icd
systemctl restart jellyfin
```

**For NVIDIA:**

NVIDIA passthrough requires more steps than Intel because the NVIDIA userspace libraries inside the container must match the kernel driver version running on the Proxmox host exactly. There is no distribution package that guarantees this match, so the libraries are mounted directly from the host filesystem into the container.

**Step 1: Install the NVIDIA driver on the Proxmox host**

Follow the standard Debian NVIDIA driver installation on the host. Confirm the driver is loaded:

```bash
nvidia-smi
```

Note the driver version from the output (e.g. `580.142`). You will need it in step 3.

**Step 2: Configure the LXC**

Add the following to `/etc/pve/lxc/<id>.conf` on the Proxmox host. These lines grant the container access to NVIDIA character devices (major 195), nvidia-uvm (235), DRI (226), framebuffer (29), and input devices (13), then bind-mount the device nodes:

```
lxc.cgroup2.devices.allow: c 195:* rwm
lxc.cgroup2.devices.allow: c 235:* rwm
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.cgroup2.devices.allow: c 29:0 rwm
lxc.cgroup2.devices.allow: c 13:* rwm
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
lxc.autodev: 1
```

Restart the LXC after saving.

**Step 3: Create the ldconfig-init.sh entrypoint script**

Inside the LXC, create `/docker/ldconfig-init.sh`. This wrapper runs `ldconfig` before Jellyfin starts so the container linker picks up the mounted host libraries:

```bash
#!/bin/sh
ldconfig
exec /init "$@"
```

Make it executable:

```bash
chmod +x /docker/ldconfig-init.sh
```

**Step 4: Write the Docker Compose file**

This approach runs Jellyfin in Docker inside the LXC rather than as a native systemd service. The `linuxserver/jellyfin` image bundles its own ffmpeg, so the NVIDIA libraries are mounted from the host as read-only volumes. Replace `580.142` throughout with the version from `nvidia-smi`.

```yaml
services:
  jellyfin:
    image: lscr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    privileged: true
    entrypoint: /ldconfig-init.sh
    environment:
      - PUID=0
      - PGID=0
      - TZ=Europe/London
    volumes:
      - /docker/ldconfig-init.sh:/ldconfig-init.sh:ro
      # NVIDIA libraries — version must match nvidia-smi output on host
      - /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.580.142:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.580.142:ro
      - /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.1:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.1:ro
      - /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so:ro
      - /usr/lib/x86_64-linux-gnu/libnvcuvid.so.580.142:/usr/lib/x86_64-linux-gnu/libnvcuvid.so.580.142:ro
      - /usr/lib/x86_64-linux-gnu/libnvcuvid.so.1:/usr/lib/x86_64-linux-gnu/libnvcuvid.so.1:ro
      - /usr/lib/x86_64-linux-gnu/libnvcuvid.so:/usr/lib/x86_64-linux-gnu/libnvcuvid.so:ro
      - /usr/lib/x86_64-linux-gnu/libcuda.so.580.142:/usr/lib/x86_64-linux-gnu/libcuda.so.580.142:ro
      - /usr/lib/x86_64-linux-gnu/libcuda.so.1:/usr/lib/x86_64-linux-gnu/libcuda.so.1:ro
      - /usr/lib/x86_64-linux-gnu/libcuda.so:/usr/lib/x86_64-linux-gnu/libcuda.so:ro
      - /usr/lib/x86_64-linux-gnu/libnvidia-encode.so.580.142:/usr/lib/x86_64-linux-gnu/libnvidia-encode.so.580.142:ro
      - /usr/lib/x86_64-linux-gnu/libnvidia-encode.so.1:/usr/lib/x86_64-linux-gnu/libnvidia-encode.so.1:ro
      - /usr/lib/x86_64-linux-gnu/libnvidia-encode.so:/usr/lib/x86_64-linux-gnu/libnvidia-encode.so:ro
      # Jellyfin config and media
      - ./library:/config
      - /mnt/jellyfin/jellyfin:/data/tvshows
      - /mnt/jellyfin/movies:/data/movies
      - /mnt/jellyfin/transcodes:/mnt/transcodes:rw
    devices:
      - /dev/dri:/dev/dri
      - /dev/nvidia0:/dev/nvidia0
      - /dev/nvidiactl:/dev/nvidiactl
      - /dev/nvidia-uvm:/dev/nvidia-uvm
      - /dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools
    ports:
      - 8096:8096
      - 8920:8920
      - 7359:7359/udp
      - 1900:1900/udp
    restart: unless-stopped
```

`privileged: true` and `PUID=0`/`PGID=0` are required. Unprivileged access to NVIDIA devices from Docker running inside an LXC does not work reliably; the container needs to run as root.

**Step 5: Enable NVENC in Jellyfin**

After the container starts, go to **Administration → Dashboard → Playback → Hardware acceleration** and select **NVIDIA NVENC**. Save and restart the container. Check the transcoding overlay in the Jellyfin player to confirm GPU usage.

## Remote access

Jellyfin does not include a built-in relay. Remote access requires a reverse proxy. If you are already using Cloudflare Tunnels, add a tunnel pointing to `http://<jellyfin-lxc-ip>:8096`, the setup is the same as for any other service in the stack.

## Result

Jellyfin is installed and connected to your media libraries. No media is available yet; that comes after configuring the download services.

Continue to [Configure Download Client (SABnzbd)](/docs/home-server/media-automation/installation/configure-sabnzbd).
