Jellyfin

Jellyfin #

Introduction #

Jellyfin is a free and open-source media server and suite of multimedia applications designed to organize, manage, and share digital media files to networked devices. It is an alternative to Emby and Plex.

This will serve as a guide to configuring Jellyfin in a Debian Proxmox LXC with hardware transcoding on Intel hardware.12

Installation #

This guide will cover the installation of Jellyfin on Debian Bullseye with non-free repositories enabled.

In my case, I will be using Debian in a Linux container (LXC) on Proxmox.

Proxmox LXC Configuration #

Ensure that you have a Debian LXC template downloaded. On Proxmox, you can do this by navigating to the storage menu on the Proxmox GUI configured for CT Templates. In a default Proxmox install, this is typically under the ’local’ storage.

Adding a container template via Proxmox VE GUI

Create a Debian CT and configure it as you would with your environment. Give it a static IP as it will be running a server.

Note: To enable hardware acceleration, Jellyfin needs to run in a privileged LXC container. Ensure that the “unprivileged” option is not enabled when initially creating the container in Proxmox.

Please note the risks of running a privileged LXC container:

Installing Jellyfin #

Main article:3 https://jellyfin.org/docs/general/installation/linux/#debian

The Jellyfin team provides a Debian repository for Buster and Bullseye. There are two options to enable this:

  1. Ensure that curl and gnupg are installed:
sudo apt install curl gnupg
  1. Download the signing key:
sudo mkdir /etc/apt/keyrings
curl -fsSL https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release )/jellyfin_team.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/jellyfin.gpg
  1. Add a repository configuration to apt:
cat <<EOF | sudo tee /etc/apt/sources.list.d/jellyfin.sources
Types: deb
URIs: https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release )
Suites: $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release )
Components: main
Architectures: $( dpkg --print-architecture )
Signed-By: /etc/apt/keyrings/jellyfin.gpg
EOF

Install extrepo and enable the jellyfin repos:

sudo apt install extrepo
sudo extrepo enable jellyfin

After enabling the repository, you can proceed to install Jellyfin:

sudo apt update
sudo apt install jellyfin

Enabling Hardware Acceleration on Proxmox LXC #

Main article:4 https://jellyfin.org/docs/general/administration/hardware-acceleration/#va-api-and-qsv-hardware-acceleration-on-lxc-on-proxmox

At this point, you should shut down the LXC container as we will be modifying its configuration.
  1. Ensure that the required drivers are installed on the Proxmox host. Since Proxmox runs on top of Debian, a simple Google search of “debian drivers for x” should assist here.

  2. Add your GPU to the container by editing /etc/pve/lxc/<container-id>.conf:5

    Versions prior to Proxmox VE 7.1 should use cgroup instead of cgroup2

lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
  1. Reboot the container.

  2. Verify that a render device is now present in /dev/dri in the container:

# ls -l /dev/dri
total 0
crw-rw---- 1 root video 226,   0 Dec 31 00:00 card0
crw-rw---- 1 root input 226, 128 Dec 31 00:00 renderD128
  1. Install jellyfin-ffmpeg and make sure it is version 4.4.1-2 or higher. This should ship with intel-media-driver, which is necessary for Intel QuickSync.6
sudo apt install jellyfin-ffmpeg5
  1. Check the output of vainfo, and make sure the iHD driver is loaded for Intel QuickSync:
sudo /usr/lib/jellyfin-ffmpeg/vainfo | grep iHD
  1. Add the jellyfin user to video, render, or the input group depending on which one owns the device in the container, as seen in step 4. Then restart Jellyfin, to allow ffmpeg to access the device. In my case it was the input group:
sudo usermod -aG input jellyfin
sudo systemctl restart jellyfin
  1. Log in to Jellyfin via the WebUI on http://{SERVER-IP}:8096, access the administrator dashboard in the settings, and under Server > Playback > Transcoding, select either VAAPI or QSV, depending on your preference.

  2. Finally, check if transcoding is enabled by opening media that requires transcoding, and looking through your logs to find ffmpeg-transcode-*.txt under /var/log/jellyfin, or the Advanced > Logs in the admin dashboard.

Web Server Configurations #

Nginx Reverse Proxy #

https://jellyfin.org/docs/general/networking/#running-jellyfin-behind-a-reverse-proxy https://jellyfin.org/docs/general/networking/nginx/

server {

    server_name jellyfin.domain.tld;

    location / {
        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-Protocol $scheme;
        proxy_set_header X-Forwarded-Host $http_host;

        proxy_buffering off;

        proxy_pass http://(SERVER-IP):8096;
    }

    location = / {
        return 302 http://$host/web/;
        #return 302 https://$host/web/;
    }

    # location block for /web - This is purely for aesthetics so /web/#!/ works instead of having to go to /web/index.html/#!/
    location = /web/ {
        # Proxy main Jellyfin traffic
        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-Protocol $scheme;
        proxy_set_header X-Forwarded-Host $http_host;

        proxy_pass http://(SERVER-IP):8096/web/index.html;
    }

    location /socket {
        # Proxy Jellyfin Websockets traffic
        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-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-Protocol $scheme;
        proxy_set_header X-Forwarded-Host $http_host;

        proxy_pass http://(SERVER-IP):8096;
    }

    client_max_body_size 20M;

    listen [::]:443 ssl http2; # managed by Certbot
    listen 443 ssl http2; # managed by Certbot
    ssl_certificate (generate these options using certbot); # managed by Certbot
    ssl_certificate_key (generate these options using certbot); # managed by Certbot
    include (generate these options using certbot); # managed by Certbot
    ssl_dhparam (generate these options using certbot); # managed by Certbot

}

Extras #

Change transcoding folder #

If Jellyfin was installed in an LXC, it is likely that a small 8-16 GB disk image was used as the root disk for the OS.

If this is the case, it is highly recommended to change the transcoding folder to another disk (which is hopefully also present, as you will likely need to store several gigabytes of media to serve.)

This can be accomplished in the admin dashboard under Server > Playback > Transcoding > Transcode path.