From 59a37c9b46442b1de67f0056a8bd396e041eb6d0 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Tue, 25 Nov 2025 19:48:52 +0100 Subject: [PATCH] feat: add jellyfin and hardware acceleration for transcoding --- hosts/fw/configuration.nix | 12 +++++++ hosts/fw/modules/dnsmasq.nix | 1 + hosts/fw/modules/pyload.nix | 59 ++++++++++++++++++++++++++++++++ hosts/fw/modules/staticids.nix | 2 ++ hosts/fw/modules/web/proxies.nix | 30 ++++++++++++++++ 5 files changed, 104 insertions(+) diff --git a/hosts/fw/configuration.nix b/hosts/fw/configuration.nix index 4728229..ecfb518 100644 --- a/hosts/fw/configuration.nix +++ b/hosts/fw/configuration.nix @@ -88,6 +88,18 @@ "ai-mailer" ]; + # Intel N100 Graphics Support for hardware transcoding + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver # VAAPI driver (iHD) for modern Intel GPUs + vpl-gpu-rt # Intel VPL/QSV runtime for Gen 12+ (N100) + intel-compute-runtime # OpenCL support for tone-mapping + ]; + }; + + hardware.enableRedistributableFirmware = true; + time.timeZone = "Europe/Vienna"; services.logind.extraConfig = "RuntimeDirectorySize=2G"; diff --git a/hosts/fw/modules/dnsmasq.nix b/hosts/fw/modules/dnsmasq.nix index f587d36..c323f0b 100644 --- a/hosts/fw/modules/dnsmasq.nix +++ b/hosts/fw/modules/dnsmasq.nix @@ -135,6 +135,7 @@ # multimedia "/dl.cloonar.com/${config.networkPrefix}.97.5" + "/jellyfin.cloonar.com/${config.networkPrefix}.97.5" "/deconz.cloonar.multimedia/${config.networkPrefix}.97.22" diff --git a/hosts/fw/modules/pyload.nix b/hosts/fw/modules/pyload.nix index bef2291..9a0b1b0 100644 --- a/hosts/fw/modules/pyload.nix +++ b/hosts/fw/modules/pyload.nix @@ -20,6 +20,7 @@ let group = "jellyfin"; home = "/var/lib/jellyfin"; createHome = true; + extraGroups = [ "render" "video" ]; }; jellyfinGroup = { gid = cids.gids.jellyfin; @@ -49,7 +50,31 @@ in hostAddress = "${networkPrefix}.97.1"; localAddress = "${networkPrefix}.97.11/24"; + # GPU device passthrough for hardware transcoding + allowedDevices = [ + { + modifier = "rwm"; + node = "/dev/dri/card0"; + } + { + modifier = "rwm"; + node = "/dev/dri/renderD128"; + } + ]; + bindMounts = { + "/dev/dri" = { + hostPath = "/dev/dri"; + isReadOnly = false; + }; + "/run/opengl-driver" = { + hostPath = "/run/opengl-driver"; + isReadOnly = true; + }; + "/nix/store" = { + hostPath = "/nix/store"; + isReadOnly = true; + }; "/var/lib/pyload" = { hostPath = "/var/lib/pyload"; isReadOnly = false; @@ -78,6 +103,21 @@ in unrar # Required for RAR archive extraction ]; + # Intel graphics support for hardware transcoding + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver + vpl-gpu-rt + intel-compute-runtime + ]; + }; + + # Set VA-API driver to iHD (modern Intel driver for N100) + environment.sessionVariables = { + LIBVA_DRIVER_NAME = "iHD"; + }; + networking = { hostName = "pyload"; useHostResolvConf = false; @@ -101,6 +141,21 @@ in openFirewall = true; }; + # Override systemd hardening for GPU access + systemd.services.jellyfin = { + serviceConfig = { + PrivateUsers = lib.mkForce false; # Disable user namespacing - breaks GPU device access + DeviceAllow = [ + "/dev/dri/card0 rw" + "/dev/dri/renderD128 rw" + ]; + SupplementaryGroups = [ "render" "video" ]; # Critical: Explicit group membership for GPU access + }; + environment = { + LIBVA_DRIVER_NAME = "iHD"; # Ensure service sees this variable + }; + }; + # Disable SSL certificate verification systemd.services.pyload = { environment = { @@ -121,6 +176,10 @@ in }; }; + # Ensure render/video groups exist with consistent GIDs for GPU access + users.groups.render = { gid = 303; }; + users.groups.video = { gid = 26; }; + users.users.pyload = pyloadUser; users.groups.pyload = pyloadGroup; users.users.jellyfin = jellyfinUser; diff --git a/hosts/fw/modules/staticids.nix b/hosts/fw/modules/staticids.nix index 57247a5..ae57ad5 100644 --- a/hosts/fw/modules/staticids.nix +++ b/hosts/fw/modules/staticids.nix @@ -6,6 +6,7 @@ podman = 10004; foundry-vtt = 10005; pyload = 10006; + jellyfin = 10007; }; gids = { unbound = 10001; @@ -14,5 +15,6 @@ podman = 10004; foundry-vtt = 10005; pyload = 10006; + jellyfin = 10007; }; } diff --git a/hosts/fw/modules/web/proxies.nix b/hosts/fw/modules/web/proxies.nix index 0ba1533..5991ea5 100644 --- a/hosts/fw/modules/web/proxies.nix +++ b/hosts/fw/modules/web/proxies.nix @@ -50,4 +50,34 @@ proxyWebsockets = true; }; }; + + services.nginx.virtualHosts."jellyfin.cloonar.com" = { + forceSSL = true; + enableACME = true; + acmeRoot = null; + + # Restrict to internal LAN only + extraConfig = '' + allow ${config.networkPrefix}.96.0/24; + allow ${config.networkPrefix}.98.0/24; + allow ${config.networkPrefix}.99.0/24; + deny all; + ''; + + locations."/" = { + proxyPass = "http://${config.networkPrefix}.97.11:8096"; + proxyWebsockets = true; + + extraConfig = '' + # Jellyfin-specific headers for proper streaming + 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 $http_host; + + # Disable buffering for better streaming performance + proxy_buffering off; + ''; + }; + }; }