{ pkgs, service_configs, config, lib, ... }: { imports = [ (lib.serviceMountWithZpool "prowlarr" service_configs.zpool_ssds [ service_configs.prowlarr.dataDir ]) (lib.vpnNamespaceOpenPort service_configs.ports.private.prowlarr.port "prowlarr") (lib.serviceFilePerms "prowlarr" [ "Z ${service_configs.prowlarr.dataDir} 0700 prowlarr prowlarr" ]) (lib.mkCaddyReverseProxy { subdomain = "prowlarr"; port = service_configs.ports.private.prowlarr.port; auth = true; vpn = true; }) ]; services.prowlarr = { enable = true; dataDir = service_configs.prowlarr.dataDir; settings.server.port = service_configs.ports.private.prowlarr.port; }; # The upstream prowlarr module uses DynamicUser=true which is incompatible # with ZFS-backed persistent storage — the dynamic user can't access files # on the ZFS mount. Override with a static user to match sonarr/radarr. users.users.prowlarr = { isSystemUser = true; group = "prowlarr"; home = service_configs.prowlarr.dataDir; }; users.groups.prowlarr = { }; # The upstream prowlarr module hardcodes root:root in tmpfiles for custom dataDirs # (systemd.tmpfiles.settings."10-prowlarr"), which gets applied by # systemd-tmpfiles-setup.service on every boot/deploy, resetting the directory # ownership and making Prowlarr unable to access its SQLite databases. # Override to use the correct user as we disable DynamicUser systemd.tmpfiles.settings."10-prowlarr".${service_configs.prowlarr.dataDir}.d = lib.mkForce { user = "prowlarr"; group = "prowlarr"; mode = "0700"; }; systemd.services.prowlarr.serviceConfig = { DynamicUser = lib.mkForce false; User = "prowlarr"; Group = "prowlarr"; StateDirectory = lib.mkForce ""; ExecStart = lib.mkForce "${lib.getExe pkgs.prowlarr} -nobrowser -data=${service_configs.prowlarr.dataDir}"; }; }