Jellyfin - Media Streaming
Jellyfin is a media streaming hub. It allows you to easily stream audio and video files to a web browser.
Access
Our Jellyfin instance is reverse-proxied by the Secure Web Application Gateway. It is published on media.kasad.com.
Deployment
Jellyfin runs as a single Docker container using the lscr.io/linuxserver/jellyfin:latest
image. It is one of the LinuxServer.io images with available mods.
We run Jellyfin using a Docker Compose file for easy configuration:
version: "3"
services:
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
ports:
- 7359:7359/udp
- 1900:1900/udp
volumes:
- /media:/media
- jellyfin_config:/config
tmpfs:
- /config/transcodes
- /config/cache
- /config/data/transcodes
devices:
# VA-API devices
- /dev/dri/card0:/dev/dri/card0
- /dev/dri/renderD128:/dev/dri/renderD128
restart: unless-stopped
environment:
- PUID=938 # swag
- PGID=941 # servlets
- UMASK=002
- TZ=America/Los_Angeles
- JELLYFIN_PublishedServerUrl=https://swag.kasad.com/jellyfin
- DOCKER_MODS=ghcr.io/kdkasad/docker-mods/jellyfin-jellyscrub
networks:
- default
- swag
volumes:
jellyfin_config: {}
networks:
swag:
name: swag_default
external: true
SWAG network
The Send container is reverse-proxied behind the Secure Web Application Gateway, so the SWAG container needs network access to the Send container. This has been done in the Compose stack above. See this explanation for details.
Persistent data storage
The lscr.io/linuxserver/jellyfin
image stores all of its data in /config
by default.
To make this persistent, we mount a volume on /config
:
volumes:
- jellyfin_config:/config
Since this is a named volume, we also need to declare it at the end of the Compose file:
volumes:
jellyfin_config: {}
Media volume
Jellyfin needs to be able to access the media it is going to stream. The media volume can be mounted anywhere within Jellyfin as long as it is configured accordingly in the UI. We mount the media volume on /media
to keep things simple.
Jellyfin needs at least read access to all media. If metadata is being stored alongside media, Jellyfin needs write access as well.
We run the Jellyfin container with a umask of 002
. This means newly created files will have user/group read-write permissions and global read permissions.
We also set the group ownership of /media
to the servlets
group. We set the SetGID flag to ensure new files/directories inherit the parent's group ownership.
In-memory caches
Some of Jellyfin's data does not need to be persistent. In order to improve performance and reduce unnecessary writes to disk, we mount temporary (in-memory) filesystems on:
-
/config/data/transcodes
- Where Jellyfin writes temporary transcoded video files -
/config/cache
- Where short-lived cache data is stored
If the system running the Jellyfin container does not have sufficient RAM, this will likely cause Jellyfin to fail (or at least cause heavy swapping) while transcoding large videos. The transcode directory should be able to fit the media being streamed, so it should be at least a few gigabytes.
VA-API devices
The host system (my laptop) that runs the Jellyfin container has an Intel iGPU which supports VA-API for hardware video decoding. To utilize this in Jellyfin, the VA-API device nodes must be accessible inside the container. This is done in the devices
section of the Compose service:
devices:
- /dev/dri/card0:/dev/dri/card0
- /dev/dri/renderD128:/dev/dri/renderD128
It should also be possible to just mount the /dev/dri
directory as a volume, but I have not tried that.
One the devices are mounted in the container, follow the Hardware-accelerated video decoding configuration instructions.
DLNA/UPnP
Jellyfin comes built with DLNA and UPnP support for streaming to wireless displays like TVs. To enable this, we forward the following ports for the container.
ports:
- 7359:7359/udp
- 1900:1900/udp
Then select Enable 'Play To' DLNA feature in the DLNA settings tab.
Despite the port forwards, it does not seem to work as well as when the Jellyfin container is run in host network mode.
Configuration
Most of Jellyfin's configuration is done from its built-in settings menu.
The only options that are not configured from there are the PID, UID, umask, and the published server URL.
These are all defined in the environment
section of the jellyfin
service in the Compose file.
File paths
Our Jellyfin instance is configured to use the following file paths. Some of these paths are default and some are manually configured in the Settings UI. However all of them are important as they have a specific filesystem mounted on them.
Path | Filesystem Type | Purpose | Where to configure |
---|---|---|---|
/config |
Named volume | Main data directory | just don't change it |
/config/data/transcodes |
tmpfs(5) |
Contains transcoded videos while they're being streamed | Playback tab |
/config/cache |
tmpfs(5) |
Temporary cached data | General tab |
/media |
Host volume (/media ) |
Media library | Each library in the Libraries tab |
All directories with volume mounts are explained in the Deployment section. This table is just meant to list them all in one place.
Storing metadata alongside media
I prefer having metadata on the same volume as the media, as most of the data is related. To accomplish this, set General > Metadata Path to /media/metadata
. Make sure the directory you choose exists.
Better theme
Jellyfin supports adding custom CSS to style the web interface. We load the Ultrachromic theme, which is an overhaul of the default Jellyfin UI.
General > Custom CSS Code:
@import url('https://cdn.jsdelivr.net/gh/CTalvio/Ultrachromic/presets/monochromic_preset.css');
Hardware-accelerated video decoding
Jellyfin has many settings for hardware-accelerated video decoding (a.k.a. HWDec) in the Playback tab of the Settings UI. Many APIs for this are supported, but I've only used VA-API, so that's the only one documented here.
VA-API (Intel GPUs)
If VA-API devices have been mounted, set the following options:
Option | Value | Description |
---|---|---|
Hardware acceleration | Video Acceleration API (VAAPI) |
Enable use of VA-API for HWDec |
Enable hardware decoding for | all codecs selected | Enable hardware decoding for all codecs* |
Enable hardware encoding | enabled | Enable hardware-accelerated video encoding* |
Enable Intel Low-Power H.264/HEVC hardware encoder | enabled | Enable low-power encoders* |
Enable encoding in HEVC format | enabled | Enable HEVC (H.265) encoder* |
*Make sure your GPU supports the codecs you've enabled. Use the following command to check which codecs your GPU supports:
$ vainfo | sed 's/VAProfile//; s/VAEntrypointVLD/decode/; s/VAEntrypointEncSlice\(LP\)\?/encode \1/'
encode LP
means low-power encoding is supported.
Single sign-on
We want to allow users to log in through the Authentik SSO portal. To do this, we must configure Jellyfin and Authentik properly.
Confguring SSO in Jellyfin
To enable SSO in Jellyfin, you must install the jellyfin-sso plugin. To do this,
Setting | Value | Description |
---|---|---|
Name of OID Provider | Authentik |
Name of the SSO provider (arbitrary) |
OID Endpoint | https://auth2.kasad.com |
URL of the OpenID Connect provider |
OpenID Client ID | (redacted) | OIDC Client ID for Jellyfin |
OID Secret | (redacted) | OIDC Client secret for Jellyfin |
Enabled | ✓ | Whether this SSO provider is enabled |
Enable Authorization by Plugin | ✓ | Let the SSO plugin assign permissions to new users |
Enable all folders | ✗ | Don't allow all users to access all libraries |
Enabled folders | Music and YouTube videos |
Allow all users to access these libraries |
Roles | empty | Don't check for a specific group to authenticate with Jellyfin |
Admin Roles | Administrators |
Users in the Administrators group are administrators |
Enable role-based folder access | ✓ | Allow access to libraries based on user's groups |
Folder Role Mapping | Role: Pirates . All libraries selected |
Allow users in the Pirates group to access all media libraries |
Role Claim | groups |
The OpenID claim to get user's roles from |
Request additional scopes | empty | Authentik exports all required information in the defaults scopes |
Set default provider | Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider |
Setting to this value prevents users from having to authenticate twice |
Configuring SSO in Authentik
We also need to configure Authentik to allow Jellyfin to authenticate against it. To do this, first create a new OpenID Connect provider in Authentik's admin interface.
Set the following settings (note that some may be under the Advanced protocol settings dropdown):
Parameter | Value | Description |
---|---|---|
Redirect URI | https://media.kasad.com/sso/OID/r/Authentik |
Sets the URL that Authentik will redirect to after succesful authentication. |
Signing Key | authentik Self-signed Certificate (RSA) |
Use the default Authentik key for signing tokens |
Issuer mode | Each provider has a different issuer, based on the application slug |
Use the same issuer URL as the OID configuration endpoint |
The last path component of the redirect URL must match the Name of OID Provider option configured in Jellyfin.
Jellyscrub (smooth video scrubbing previews)
By default, Jellyfin can only show the chapter thumbnail when hovering over the video scrub bar. The Jellyscrub plugin provides smooth scrub previews.
To install it,
The plugin also requires a modification to Jellyfin's defualt index.html
file.
In order for this modification to be made automatically (and persist across container restarts),
I've created a Docker mod to handle this.
To enable it, add ghcr.io/kdkasad/docker-mods:jellyfin-jellyscrub
to the DOCKER_MODS
environment variable for the jellyfin
container.
Using Jellyfin
The following sections contain information pertaining to using Jellyfin once it's set up.
Logging in with SSO
There's one problem with SSO support in Jellyfin.
Since it's provided via a plugin and not by Jellyfin itself, SSO isn't enabled on the login page.
To log in with SSO, a user must visit this URL: https://media.kasad.com/sso/OID/p/Authentik
.
To make this easier, I've configured the Secure Web Application Gateway reverse proxy to redirect from https://media.kasad.com/login
to https://media.kasad.com/sso/OID/p/Authentik
. This allows users to simply visit https://media.kasad.com/login
. So far, I've not found a way to automatically redirect from the root page to the SSO login page without breaking the SSO log-in process.
Again, the last path component of the redirect URL must match the Name of OID Provider option configured in Jellyfin.
No Comments