Files

126 lines
4.2 KiB
Nix

{ config
, pkgs
, lib
, ...
}:
let
# Jellyfin SSO plugin built from upstream release zip.
# Not in nixpkgs, so we package it here for use in a bind mount.
ssoPlugin = pkgs.stdenvNoCC.mkDerivation {
pname = "jellyfin-plugin-sso";
version = "4.0.0.4";
src = pkgs.fetchzip {
url = "https://github.com/9p4/jellyfin-plugin-sso/releases/download/v4.0.0.4/sso-authentication_4.0.0.4.zip";
hash = "sha256-MJTyE6CeVLk7mlugauJ/F6bpi1kYwNtzNmQeH3+CFeQ=";
stripRoot = false;
};
dontBuild = true;
installPhase = ''
mkdir -p $out
cp -r ./* $out/
'';
};
# Plugin directory name expected by Jellyfin (version-specific).
pluginDirName = "SSO-Auth_4.0.0.4";
in
{
options.services.jellyfin-server = {
enable = lib.mkEnableOption "Jellyfin media server";
port = lib.mkOption {
type = lib.types.port;
default = 8096;
description = "Port for Jellyfin web interface";
};
mediaLocation = lib.mkOption {
type = lib.types.path;
default = "/data/jellyfin";
description = "Directory for storing media files";
};
};
config = lib.mkIf config.services.jellyfin-server.enable {
services.jellyfin = {
enable = true;
openFirewall = true;
group = "jellyfin";
# Hardware acceleration for NVIDIA NVENC transcoding (GTX 960 on homeserver-1).
# Requires the legacy_580 driver branch for Maxwell GPUs.
hardwareAcceleration = {
enable = true;
type = "nvenc";
device = "/dev/nvidia0";
};
# Force encoding config so NVENC settings are applied on every restart.
# Without this, changes made in the web UI persist, but NixOS settings are ignored.
forceEncodingConfig = true;
transcoding = {
# Enable hardware encoding for H.264 and H.265 (HEVC).
enableHardwareEncoding = true;
# Optional: enable tone mapping for HDR → SDR conversion.
enableToneMapping = false;
};
};
# Media dir: petere writes via Samba (forced to group jellyfin), Jellyfin
# reads as group jellyfin. Not world-writable.
# Also ensure the plugins directory exists for the SSO plugin bind mount.
systemd.tmpfiles.rules = [
"d ${config.services.jellyfin-server.mediaLocation} 0775 root jellyfin -"
"d /var/lib/jellyfin/plugins 0755 jellyfin jellyfin -"
];
# Samba share is authenticated and restricted to petere (the only writer).
# No guest access; the Samba password is managed via SOPS (see
# samba-petere-password secret and the samba-set-password service below).
services.samba = {
enable = true;
openFirewall = true;
settings = {
global = {
"server role" = "standalone server";
security = "user";
};
jellyfin = {
path = "${config.services.jellyfin-server.mediaLocation}";
browseable = "yes";
"read only" = "no";
"guest ok" = "no";
"valid users" = "petere";
"force group" = "jellyfin";
"force create mode" = "0664";
"force directory mode" = "0775";
};
};
};
# Install the SSO plugin by copying from the Nix store.
# Jellyfin needs to write plugin metadata (meta.json), so we can't use
# a read-only bind mount from /nix/store. This oneshot service is
# idempotent: it only copies if the plugin dir doesn't exist or differs.
systemd.services.jellyfin-install-plugin-sso = {
description = "Install Jellyfin SSO Auth plugin";
wantedBy = [ "multi-user.target" ];
before = [ "jellyfin.service" ];
serviceConfig.Type = "oneshot";
script = ''
PLUGIN_DIR="/var/lib/jellyfin/plugins/${pluginDirName}"
SOURCE="${ssoPlugin}"
# Only copy if the plugin doesn't exist or source changed
if [ ! -d "$PLUGIN_DIR" ] || ! diff -rq "$SOURCE" "$PLUGIN_DIR" >/dev/null 2>&1; then
rm -rf "$PLUGIN_DIR"
cp -r "$SOURCE" "$PLUGIN_DIR"
chown -R jellyfin:jellyfin "$PLUGIN_DIR"
chmod -R u+w "$PLUGIN_DIR"
fi
'';
};
systemd.services.jellyfin = {
after = [ "jellyfin-install-plugin-sso.service" ];
wants = [ "jellyfin-install-plugin-sso.service" ];
};
};
}