Adding Jellyfin

Posted April 26, 2024 by smnd ‐ 3 min read

Adding Jellyfin to my Stack

Why Jellyfin?

Jellyfin is a great media player, which can be selfhosted, and makes it possible to play media from the mounted volumes of the container through the web.

So what did I need to do? The containers I run are managed by systemd. My server is generally off, and in order to have my services up and running when I turn on the server systemd provides the possibility to auto-start and auto-update rootless containers.

First let's create the needed container file in the user directory ( we want rootless).

~/.config/systemd/jellyfin.container:

[Container]
Image=docker.io/jellyfin/jellyfin:latest
AutoUpdate=registry
PublishPort=8096:8096
Volume=jellyfin-config:/config:Z
Volume=jellyfin-cache:/cache:Z
Volume=/path/to/movies:/movies:z
Volume=/path/to/series:/tv:z
Volume=/path/to/youtube-dlp:/youtube-dlp:z

User=1000:1002
UserNS=keep-id

[Service]
Restart=always
# Inform systemd of additional exit status
SuccessExitStatus=0 143

[Unit]
Wants=network-online.target nss-lookup.target
After=network-online.target nss-lookup.target

[Install]
WantedBy=default.target

then we can add the firewall exception:

sudo firewall-cmd --add-port 8096/tcp -- permanent

for starting the container run these commands:

systemctl --user daemon-reload
systemctl --user start jellyfin

Then in the Podman containers view we should see the container up and running. Setting up a reverse proxy running as root:

/path/to/the/volume/mounted/in/the/nginx/container/etc/nginx/conf.d/jellyfin.conf:

server {
    listen 80;
    listen [::]:80;
    server_name subdomain.domain.tld;

    location /{
	proxy_pass http://server.ip.address.and:port;
    }
}

or if you already have your ssl certs:

server {
    listen 80;
    listen [::]:80;
    server_name subdomain.domain.tld;

    location /{
        add_header alt-svc 'h3=":443"; ma=86400';
        return 301 https://subdomain.domain.tld$request_uri;
    }
}
server {
    http3 on;
    http3_hq on;
    listen 443 ssl http2;
    listen 443 quic;

    include conf.d/http3.conf;
    server_name  subdomain.domain.tld;

    # Specify SSL
    ssl_certificate /etc/ssl/subdomain.domain.tld/subdomain.domain.tld.crt;
    ssl_certificate_key /etc/ssl/subdomain.domain.tld/subdomain.domain.tld.key;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location /{
    # Add Alt-Svc headers to negotiate HTTP/3
    add_header Alt-Svc 'h3=":443"; ma=3600';
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $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-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Ssl on;
	proxy_pass server.ip.address.and:port;
    }
}

after adding this we need to be aware that the selinux context may need to be updated, so that nginx may reach the file we have created, and reloaded before restarting nginx service.

sudo semanage fcontext -a -t httpd_sys_content_t '/path/to/nginx/stuff/nginx/etc/nginx(/.*)?'
sudo restorecon -Rv /path/to/nginx/stuff/nginx/etc/nginx/

then restart nginx:

sudo systemctl restart nginx

Once the container is up and running, it should be possible to reach it under the subdomain.domain.tld (whatever we have chosen here).