Jellyfin Service
Defined in /modules/services/jellyfin.nix.
This NixOS module is a service that sets up a Jellyfin instance.
Compared to the stock module from nixpkgs, this one sets up, in a fully declarative manner:
the initial wizard with an admin user thanks to a custom Jellyfin CLI and a custom restart logic to apply the changes from the CLI.
LDAP and SSO integration thanks to a custom declarative installation of plugins.
Features
Declarative creation of admin user.
Declarative selection of listening port.
Access through subdomain and HTTPS using reverse proxy. Manual.
Declarative plugin installation. Manual.
Declarative LDAP configuration.
Declarative SSO configuration.
Backup through the backup block. Manual.
Integration with the dashboard contract for displaying user facing application in a dashboard. Manual
Usage
Initial Configuration
The following snippet assumes a few blocks have been setup already:
the secrets block with SOPS,
the
shb.sslblock,the
shb.lldapblock.the
shb.autheliablock.
shb.jellyfin = {
enable = true;
subdomain = "jellyfin";
domain = "example.com";
admin = {
username = "admin";
password.result = config.shb.sops.secret."jellyfin/adminPassword".result;
};
ldap = {
enable = true;
host = "127.0.0.1";
port = config.shb.lldap.ldapPort;
dcdomain = config.shb.lldap.dcdomain;
adminPassword.result = config.shb.sops.secret."jellyfin/ldap/adminPassword".result
};
sso = {
enable = true;
endpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
secretFile = config.shb.sops.secret."jellyfin/sso_secret".result;
secretFileForAuthelia = config.shb.sops.secret."jellyfin/authelia/sso_secret".result;
};
};
shb.sops.secret."jellyfin/adminPassword".request = config.shb.jellyfin.admin.password.request;
shb.sops.secret."jellyfin/ldap/adminPassword".request = config.shb.jellyfin.ldap.adminPassword.request;
shb.sops.secret."jellyfin/sso_secret".request = config.shb.jellyfin.sso.sharedSecret.request;
shb.sops.secret."jellyfin/authelia/sso_secret" = {
request = config.shb.jellyfin.sso.sharedSecretForAuthelia.request;
settings.key = "jellyfin/sso_secret";
};
Secrets can be randomly generated with nix run nixpkgs#openssl -- rand -hex 64.
The user and admin LDAP groups are created automatically.
The shb.jellyfin.sso.secretFile and shb.jellyfin.sso.secretFileForAuthelia options
must have the same content. The former is a file that must be owned by the jellyfin user while
the latter must be owned by the authelia user. I want to avoid needing to define the same secret
twice with a future secrets SHB block.
Certificates
For Let’s Encrypt certificates, add:
{
shb.certs.certs.letsencrypt.${domain}.extraDomains = [
"${config.shb.jellyfin.subdomain}.${config.shb.jellyfin.domain}"
];
}
Backup
Backing up Jellyfin using the Restic block is done like so:
shb.restic.instances."jellyfin" = {
request = config.shb.jellyfin.backup;
settings = {
enable = true;
};
};
The name "jellyfin" in the instances can be anything.
The config.shb.jellyfin.backup option provides what directories to backup.
You can define any number of Restic instances to backup Jellyfin multiple times.
You will then need to configure more options like the repository,
as explained in the restic documentation.
Impermanence
To save the data folder in an impermanence setup, add:
{
shb.zfs.datasets."safe/jellyfin".path = config.shb.jellyfin.impermanence;
}
Declarative LDAP
To add a user USERNAME to the user and admin groups for jellyfin, add:
shb.lldap.ensureUsers.USERNAME.groups = [
config.shb.jellyfin.ldap.userGroup
config.shb.jellyfin.ldap.adminGroup
];
Application Dashboard
Integration with the dashboard contract is provided by the dashboard option.
For example using the Homepage service:
{
shb.homepage.servicesGroups.Media.services.Jellyfin = {
sortOrder = 1;
dashboard.request = config.shb.jellyfin.dashboard.request;
};
}
An API key can be set to show extra info:
{
shb.homepage.servicesGroups.Media.services.Jellyfin = {
apiKey.result = config.shb.sops.secret."jellyfin/homepageApiKey".result;
};
shb.sops.secret."jellyfin/homepageApiKey".request =
config.shb.homepage.servicesGroups.Media.services.Jellyfin.apiKey.request;
}
Debug
In case of an issue, check the logs for systemd service jellyfin.service.
Enable verbose logging by setting the shb.jellyfin.debug boolean to true.
Options Reference
-
shb.jellyfin.enable -
Whether to enable shb jellyfin.
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin -
Default admin user info. Only needed if LDAP or SSO is not configured.
Type: null or (submodule)
Default:
nullDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password -
Password of the default admin user.
Type: submodule
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.request -
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.request.group -
Linux group owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.request.mode -
Mode of the secret file.
Type: string
Default:
"0440"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.request.owner -
Linux user owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.request.restartUnits -
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[ "jellyfin.service" ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.result -
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{ path = "/run/secrets/secret"; }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.password.result.path -
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.admin.username -
Username of the default admin user.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup -
Backup configuration.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request -
Request part of the backup contract.
Options set by the requester module enforcing how to backup files.
Type: submodule
Default: { user = jellyfin; sourceDirectories = [ “services.jellyfin.dataDir” ] ; excludePatterns = [ ]; hooks.beforeBackup = [ ]; hooks.afterBackup = [ ]; };
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.excludePatterns -
File patterns to exclude.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.hooks -
Hooks to run around the backup.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.hooks.afterBackup -
Hooks to run after backup.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.hooks.beforeBackup -
Hooks to run before backup.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.sourceDirectories -
Directories to backup.
Type: non-empty (list of string)
Default: [ “services.jellyfin.dataDir” ]
Example:
"/var/lib/vaultwarden"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.request.user -
Unix user doing the backups.
Type: string
Default:
"jellyfin"Example:
"vaultwarden"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.result -
Result part of the backup contract.
Options set by the provider module that indicates the name of the backup and restore scripts.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.result.backupService -
Name of service backing up the database.
This script can be ran manually to backup the database:
$ systemctl start backup.serviceType: string
Default:
"backup.service"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.backup.result.restoreScript -
Name of script that can restore the database. One can then list snapshots with:
$ restore snapshots <snapshot 1> <metadata> <snapshot 2> <metadata>And restore the database with:
$ restore restore <snapshot 1>Type: string
Default:
"restore"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.dashboard -
Dashboard contract consumer
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.dashboard.request -
Request part of the dashboard contract.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.dashboard.request.externalUrl -
URL at which the service can be accessed.
This URL should go through the reverse proxy.
Type: string
Default:
"https://\${config.shb.jellyfin.subdomain}.\${config.shb.jellyfin.domain}"Example:
"https://jellyfin.example.com"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.dashboard.request.internalUrl -
URL at which the service can be accessed directly.
This URL should bypass the reverse proxy. It can be used for example to ping the service and making sure it is up and running correctly.
Type: null or string
Default:
"http://127.0.0.1:8096"Example:
"http://127.0.0.1:8081"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.dashboard.result -
Result part of the dashboard contract.
No option is provided here.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.debug -
Enable debug logging
Type: boolean
Default:
falseDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.domain -
Domain to serve sites under.
Type: string
Example:
"domain.com"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap -
LDAP configuration.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.enable -
Whether to enable LDAP.
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminGroup -
LDAP admin group
Type: string
Default:
"jellyfin_admin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword -
LDAP admin password.
Type: submodule
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.request -
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.request.group -
Linux group owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.request.mode -
Mode of the secret file.
Type: string
Default:
"0440"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.request.owner -
Linux user owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.request.restartUnits -
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[ "jellyfin.service" ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.result -
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{ path = "/run/secrets/secret"; }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.adminPassword.result.path -
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.dcdomain -
DC domain for LDAP.
Type: string
Example:
"dc=mydomain,dc=com"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.host -
Host serving the LDAP server.
Type: string
Example:
"127.0.0.1"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.plugin -
Pluging used for LDAP authentication.
Type: package
Default:
<derivation jellyfin-plugin-ldapauth-22>Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.port -
Port where the LDAP server is listening.
Type: signed integer
Example:
389Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ldap.userGroup -
LDAP user group
Type: string
Default:
"jellyfin_user"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.plugins -
Install plugins declaratively.
The LDAP and SSO plugins will be added if their respective shb.jellyfin.ldap.enable and shb.jellyfin.sso.enable options are set to true.
The interface for plugin creation is WIP. Feel free to add yours following the examples from the LDAP and SSO plugins but know that they may require some tweaks later on. Notably, configuration is not yet handled by this option so that will be added in the future.
Each plugin’s meta.json must be writeable because Jellyfin appends some information upon installing the plugin, like its active or disabled status. SHB automatically enables the plugin and deletes any plugin with the same prefix but other versions. Note that SHB does not attempt to find which version is latest. If twice the same plugin is added, the last one in the “plugins” list wins.
Type: list of package
Default:
[ ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.port -
Listen on port.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
8096Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ssl -
Path to SSL files
Type: null or (open submodule of anything)
Default:
nullDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ssl.paths -
Paths where the files for the certificate will be located.
This option is the contract output of the
shb.certs.certsSSL block.Type: open submodule of anything
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ssl.paths.cert -
Path to the cert file.
Type: absolute path
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ssl.paths.key -
Path to the key file.
Type: absolute path
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.ssl.systemdService -
Systemd oneshot service used to generate the certificate. Ends with the
.servicesuffix.Use this if downstream services must wait for the certificates to be generated before starting.
Type: string
Example:
"cert-generator.service"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso -
SSO configuration.
Type: submodule
Default:
{ }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.enable -
Whether to enable SSO.
Type: boolean
Default:
falseExample:
trueDeclared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.authorization_policy -
Require one factor (password) or two factor (device) authentication.
Type: one of “one_factor”, “two_factor”
Default:
"one_factor"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.clientID -
Client ID for the OIDC endpoint
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.endpoint -
OIDC endpoint for SSO
Type: string
Example:
"https://authelia.example.com"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.plugin -
Pluging used for SSO authentication.
Type: package
Default:
<derivation jellyfin-plugin-sso-4.0.0.3>Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.provider -
OIDC provider name
Type: string
Default:
"Authelia"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret -
OIDC shared secret for Jellyfin.
Type: submodule
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.request -
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.request.group -
Linux group owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.request.mode -
Mode of the secret file.
Type: string
Default:
"0440"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.request.owner -
Linux user owning the secret file.
Type: string
Default:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.request.restartUnits -
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[ "jellyfin.service" ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.result -
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{ path = "/run/secrets/secret"; }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecret.result.path -
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia -
OIDC shared secret for Authelia.
Type: submodule
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.request -
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default: { mode = 0400; owner = config.shb.authelia.autheliaUser; group = root; restartUnits = [ ]; }
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.request.group -
Linux group owning the secret file.
Type: string
Default:
"root"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.request.mode -
Mode of the secret file.
Type: string
Default:
"0400"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.request.owner -
Linux user owning the secret file.
Type: string
Default: config.shb.authelia.autheliaUser
Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.request.restartUnits -
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[ ]Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.result -
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{ path = "/run/secrets/secret"; }Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.sso.sharedSecretForAuthelia.result.path -
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"Declared by:
<selfhostblocks/modules/services/jellyfin.nix> -
shb.jellyfin.subdomain -
Subdomain under which home-assistant will be served.
Type: string
Example:
"jellyfin"Declared by:
<selfhostblocks/modules/services/jellyfin.nix>