Note
This project will probably be unmaintained soon. Consider using Jellar instead, as it solves some of the fundamental problems this project have. You can read more about why in Jellar's README.
This repository provides a Nix flake that allows for declarative configuration of Users, Libraries, Settings, etc.
- Declarative users
- permissions
- Libraries
- User specific library access
- Server Settings
- System
- Network
- Encoding (HW acceleration)
- Branding settings
- Automatic backups
- API keys
Automatically generated documentation outlining all options is available in documentation.md
Frequently asked questions and common problems are documented in FAQ.md
Add the flake to your inputs and import the nixosModule in your configuration.
Example minimal flake.nix:
{
description = "An example using declarative-jellyfin flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
declarative-jellyfin.url = "github:Sveske-Juice/declarative-jellyfin";
};
outputs = {
nixpkgs,
declarative-jellyfin,
...
}: {
nixosConfigurations."your-hostname" = nixpkgs.lib.nixosSystem {
modules = [
declarative-jellyfin.nixosModules.default # <- this imports the NixOS module that provides the options
./configuration.nix # <- your host entrypoint
];
};
};
}See the example directory for example configs.
You can configure system settings through the services.declarative-jellyfin.system options.
Example:
services.declarative-jellyfin.system = {
serverName = "My Declarative Jellyfin Server";
# Use Hardware Acceleration for trickplay image generation
trickplayOptions = {
enableHwAcceleration = true;
enableHwEncoding = true;
};
UICulture = "da"; # Make the UI language danish
};You can configure users with the options provided by services.declarative-jellyfin.users.
Example:
services.declarative-jellyfin.users = {
admin = {
mutable = false; # overwrite user settings
permissions.isAdministrator = true;
hashedPasswordFile = config.sops.secrets.jellyfin-admin-passwd.path;
};
"Alice Doe" = {
password = "123"; # WARNING: plain text!
permissions.enableMediaPlayback = false; # this user is not allowed to play media
};
};Note
When users.<name>.mutable = true (default), the settings configured in your nix configuration will only be applied
once when the user is first generated. You can therefore use the GUI to configure the user if you please. When
users.<name>.mutable = false every user setting will be overwritten when jellyfin starts. This can be usefull if
you want a user to be fully declarative (for example admin accounts).
Jellyfin uses pbkdf2-sha512 hashes to store passwords.
Use the genhash script bundled in this flake with the parameters the jellyfin DB expects:
$ nix run github:Sveske-Juice/declarative-jellyfin#genhash -- -i 210000 -l 128 -u -k "your super secret password"Extract the secret and use the hashedPasswordFile:
sops.secrets.example-user-password = {
owner = config.services.jellyfin.user;
group = config.services.jellyfin.group;
};
services.declarative-jellyfin.users.example-user.hashedPasswordFile = config.sops.secrets.example-user-password.path;You can configure libraries with the options provided by services.declarative-jellyfin.libraries.
Below are some examples of different types of libraries:
Movies
services.declarative-jellyfin.libraries.Movies = {
enabled = true;
contentType = "movies";
pathInfos = ["/data/Movies"];
};TV Shows
services.declarative-jellyfin.libraries.Shows = {
enabled = true;
contentType = "tvshows";
pathInfos = ["/data/Shows"];
};Home Videos and Photos
services.declarative-jellyfin.libraries."Family photos" = {
enabled = true;
contentType = "homevideos";
pathInfos = ["/data/Famility/Photos" "/data/Family/Videos"];
};Books
services.declarative-jellyfin.libraries.Books = {
enabled = true;
contentType = "books";
pathInfos = ["/data/Books"];
};Music
services.declarative-jellyfin.libraries.Music = {
enabled = true;
contentType = "music";
pathInfos = ["/data/Music"];
};See the source code for possible library content types.
Note
By declaring libraries through your nixos configuration, any changes through the GUI will be overwritten by restarting jellyfin. If you want to change settings through the GUI, you must not specify the library in your configuration, otherwise you've to specify the options in the config.
To whitelist the libraries the user have access to, you can use services.declarative-jellyfin.users.<name>.preferences.enabledLibraries:
services.declarative-jellyfin.users.your-username = {
# ...
preferences = {
enabledLibraries = ["Movies" "Photos and Videos"]; # Libraries that the user has access to
};
permissions = {
enableAllFolders = false;
};
};It's important to disable permissions.enableAllFolders otherwise the preferences won't have any effect.
First figure out what HW acceleration methods your system supports: https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/
Then configure the options through services.declarative-jellyfin.encoding.
# AMD VA-API and VDPAU should work out of the box with mesa
hardware.graphics.enable = true;
users.users.${config.services.jellyfin.user}.extraGroups = ["video" "render"];
services.declarative-jellyfin = {
# ... other configuration ...
encoding = {
enableHardwareEncoding = true;
hardwareAccelerationType = "vaapi";
enableDecodingColorDepth10Hevc = true; # enable if your system supports
allowHevcEncoding = true; # enable if your system supports
allowAv1Encoding = true; # enable if your system supports
hardwareDecodingCodecs = [ # enable the codecs your system supports
"h264"
"hevc"
"mpeg2video"
"vc1"
"vp9"
"av1"
];
};
};Use vainfo from libva-utils to see the codec capabilities for your VA-API device.
Caution
At the moment only plugin repositories can be configured with this flake. For now you have to imperatively install and configure plugins.
Plugins are very difficult to manage declaratively, so for now you can only manage the plugin repositories declaratively
services.declarative-jellyfin = {
system.pluginRepositories = [
{
content = {
Name = "Jellyfin Stable";
Url = "https://repo.jellyfin.org/files/plugin/manifest.json";
};
tag = "RepositoryInfo"; # Needed to generate the correct XML
}
{
content = {
Name = "Intro Skipper";
Url = "https://intro-skipper.org/manifest.json";
};
tag = "RepositoryInfo"; # Needed to generate the correct XML
}
];
};This will download the specified verson of the plugin and install it for you during evaluation.
This is still not possible, but is being worked on.
Declarative Jellyfin is designed to be a drop-in replacement for the normal jellyfin service.
- services.jellyfin = {
+ services.declarative-jellyfin = {Warning
Always use keyPath together with a secret manager, instead of storing api keys in plaintext with key.
Example:
services.declarative-jellyfin.apikeys = {
Jellyseerr = {
keyPath = config.sops.secrets.my-jellyfin-jellyseerr-key.path;
};
"Homarr Dashboard" = {
key = "78878bf9fc654ff78ae332c63de5aeb6"; # WARNING: plain-text!
};
};Don't know why this happens. A workaround is to restart jellyfin (through the dashboard, restarting the service doesn't count) which will make it work again for a while.