diff --git a/nixarr/default.nix b/nixarr/default.nix index 1e97de4..cc112ad 100644 --- a/nixarr/default.nix +++ b/nixarr/default.nix @@ -82,6 +82,10 @@ with lib; let chown -R readarr:root "${cfg.readarr.stateDir}" find "${cfg.readarr.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) '' + + strings.optionalString cfg.readarr-audiobook.enable '' + chown -R readarr:root "${cfg.readarr-audiobook.stateDir}" + find "${cfg.readarr-audiobook.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) + '' + strings.optionalString cfg.jellyseerr.enable '' chown -R jellyseerr:root "${cfg.jellyseerr.stateDir}" find "${cfg.jellyseerr.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) @@ -109,6 +113,7 @@ in { ./prowlarr ./radarr ./readarr + ./readarr-audiobook ./recyclarr ./sabnzbd ./sonarr @@ -150,12 +155,13 @@ in { - [Prowlarr](#nixarr.prowlarr.enable) - [Radarr](#nixarr.radarr.enable) - [Readarr](#nixarr.readarr.enable) + - [Readarr Audiobook](#nixarr.readarr-audiobook.enable) - [Recyclarr](#nixarr.recyclarr.enable) - [SABnzbd](#nixarr.sabnzbd.enable) - [Sonarr](#nixarr.sonarr.enable) - [Transmission](#nixarr.transmission.enable) - Remember to read the options. + Remember to read the options! ''; }; diff --git a/nixarr/prowlarr/default.nix b/nixarr/prowlarr/default.nix index b1c0cbb..6a1ed81 100644 --- a/nixarr/prowlarr/default.nix +++ b/nixarr/prowlarr/default.nix @@ -5,26 +5,31 @@ ... }: with lib; let - defaultPort = 9696; - nixarr = config.nixarr; cfg = config.nixarr.prowlarr; + nixarr = config.nixarr; + uid = 293; + port = 9696; in { - imports = [ - ./prowlarr-module - ]; - options.nixarr.prowlarr = { enable = mkOption { type = types.bool; default = false; example = true; description = '' - Whether or not to enable the Prowlarr service. + Whether or not to enable the Prowlarr service. This has + a seperate service since running two instances is the standard + way of being able to query both ebooks and audiobooks. ''; }; package = mkPackageOption pkgs "prowlarr" {}; + port = mkOption { + type = types.port; + default = port; + description = "Port for Prowlarr to use."; + }; + stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/prowlarr"; @@ -75,29 +80,52 @@ in { } ]; - util-nixarr.services.prowlarr = { - enable = true; - package = cfg.package; - openFirewall = cfg.openFirewall; - dataDir = cfg.stateDir; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + + systemd.services.prowlarr = { + description = "prowlarr"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + environment = { + PROWLARR__SERVER__PORT = cfg.port; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.stateDir}"; + Restart = "on-failure"; + }; }; + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [cfg.port]; + }; + + users.users.prowlarr = { + group = "prowlarr"; + home = cfg.stateDir; + uid = uid; + }; + users.groups.prowlarr = {}; + # Enable and specify VPN namespace to confine service in. systemd.services.prowlarr.vpnConfinement = mkIf cfg.vpn.enable { enable = true; vpnNamespace = "wg"; }; - # Port mappings vpnNamespaces.wg = mkIf cfg.vpn.enable { portMappings = [ { - from = defaultPort; - to = defaultPort; + from = cfg.port; + to = cfg.port; } ]; }; - services.nginx = mkIf cfg.vpn.enable { enable = true; @@ -105,17 +133,17 @@ in { recommendedOptimisation = true; recommendedGzipSettings = true; - virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { + virtualHosts."127.0.0.1:${builtins.toString cfg.port}" = { listen = [ { addr = "0.0.0.0"; - port = defaultPort; + port = cfg.port; } ]; locations."/" = { recommendedProxySettings = true; proxyWebsockets = true; - proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; + proxyPass = "http://192.168.15.1:${builtins.toString cfg.port}"; }; }; }; diff --git a/nixarr/prowlarr/prowlarr-module/default.nix b/nixarr/prowlarr/prowlarr-module/default.nix deleted file mode 100644 index d327a94..0000000 --- a/nixarr/prowlarr/prowlarr-module/default.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -with lib; let - cfg = config.util-nixarr.services.prowlarr; -in { - options = { - util-nixarr.services.prowlarr = { - enable = mkEnableOption "Prowlarr"; - - package = mkPackageOption pkgs "prowlarr" {}; - - user = mkOption { - type = types.str; - default = "prowlarr"; - description = "User account under which Prowlarr runs."; - }; - - group = mkOption { - type = types.str; - default = "prowlarr"; - description = "Group under which Prowlarr runs."; - }; - - dataDir = mkOption { - type = types.str; - default = "/var/lib/prowlarr"; - description = "The directory where Prowlarr stores its data files."; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = "Open ports in the firewall for the Prowlarr web interface."; - }; - }; - }; - - config = mkIf cfg.enable { - systemd.tmpfiles.rules = [ - "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" - ]; - - systemd.services.prowlarr = { - description = "Prowlarr"; - after = ["network.target"]; - wantedBy = ["multi-user.target"]; - - serviceConfig = { - Type = "simple"; - User = cfg.user; - Group = cfg.group; - ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.dataDir}"; - Restart = "on-failure"; - }; - }; - - networking.firewall = mkIf cfg.openFirewall { - allowedTCPPorts = [9696]; - }; - - users.users = mkIf (cfg.user == "prowlarr") { - prowlarr = { - group = cfg.group; - home = cfg.dataDir; - uid = 293; - }; - }; - - users.groups = mkIf (cfg.group == "prowlarr") { - prowlarr = {}; - }; - }; -} diff --git a/nixarr/readarr-audiobook/default.nix b/nixarr/readarr-audiobook/default.nix new file mode 100644 index 0000000..a3da61b --- /dev/null +++ b/nixarr/readarr-audiobook/default.nix @@ -0,0 +1,151 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.nixarr.readarr-audiobook; + nixarr = config.nixarr; + uid = 269; + port = 9494; +in { + options.nixarr.readarr-audiobook = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether or not to enable the Readarr Audiobook service. This has + a seperate service since running two instances is the standard + way of being able to query both ebooks and audiobooks. + ''; + }; + + package = mkPackageOption pkgs "readarr" {}; + + port = mkOption { + type = types.port; + default = port; + description = "Port for Readarr Audiobook to use."; + }; + + stateDir = mkOption { + type = types.path; + default = "${nixarr.stateDir}/readarr-audiobook"; + defaultText = literalExpression ''"''${nixarr.stateDir}/readarr-audiobook"''; + example = "/nixarr/.state/readarr-audiobook"; + description = '' + The location of the state directory for the Readarr Audiobook service. + + > **Warning:** Setting this to any path, where the subpath is not + > owned by root, will fail! For example: + > + > ```nix + > stateDir = /home/user/nixarr/.state/readarr-audiobook + > ``` + > + > Is not supported, because `/home/user` is owned by `user`. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + defaultText = literalExpression ''!nixarr.readarr-audiobook.vpn.enable''; + default = !cfg.vpn.enable; + example = true; + description = "Open firewall for Readarr Audiobook"; + }; + + vpn.enable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + **Required options:** [`nixarr.vpn.enable`](#nixarr.vpn.enable) + + Route Readarr Audiobook traffic through the VPN. + ''; + }; + }; + + config = mkIf (nixarr.enable && cfg.enable) { + assertions = [ + { + assertion = cfg.vpn.enable -> nixarr.vpn.enable; + message = '' + The nixarr.readarr-audiobook.vpn.enable option requires the + nixarr.vpn.enable option to be set, but it was not. + ''; + } + ]; + + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + + systemd.services.readarr-audiobook = { + description = "Readarr-Audiobook"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + environment = { + READARR__SERVER__PORT = cfg.port; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.stateDir}"; + Restart = "on-failure"; + }; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [cfg.port]; + }; + + users.users.readarr-audiobook = { + group = "readarr-audiobook"; + home = cfg.stateDir; + uid = uid; + }; + users.groups.readarr-audiobook = {}; + + # Enable and specify VPN namespace to confine service in. + systemd.services.readarr-audiobook.vpnConfinement = mkIf cfg.vpn.enable { + enable = true; + vpnNamespace = "wg"; + }; + + vpnNamespaces.wg = mkIf cfg.vpn.enable { + portMappings = [ + { + from = cfg.port; + to = cfg.port; + } + ]; + }; + services.nginx = mkIf cfg.vpn.enable { + enable = true; + + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + + virtualHosts."127.0.0.1:${builtins.toString cfg.port}" = { + listen = [ + { + addr = "0.0.0.0"; + port = cfg.port; + } + ]; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://192.168.15.1:${builtins.toString cfg.port}"; + }; + }; + }; + }; +} diff --git a/nixarr/readarr/default.nix b/nixarr/readarr/default.nix index 5241b90..f314481 100644 --- a/nixarr/readarr/default.nix +++ b/nixarr/readarr/default.nix @@ -7,7 +7,8 @@ with lib; let cfg = config.nixarr.readarr; nixarr = config.nixarr; - defaultPort = 8787; + uid = 250; + port = 8787; in { options.nixarr.readarr = { enable = mkOption { @@ -21,6 +22,12 @@ in { package = mkPackageOption pkgs "readarr" {}; + port = mkOption { + type = types.port; + default = port; + description = "Port for Readarr to use."; + }; + stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/readarr"; @@ -71,31 +78,52 @@ in { } ]; - services.readarr = { - enable = cfg.enable; - package = cfg.package; - user = "readarr"; - group = "media"; - openFirewall = cfg.openFirewall; - dataDir = cfg.stateDir; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + + systemd.services.readarr = { + description = "Readarr"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + environment = { + READARR__SERVER__PORT = cfg.port; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.stateDir}"; + Restart = "on-failure"; + }; }; + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [cfg.port]; + }; + + users.users.readarr = { + group = "readarr"; + home = cfg.stateDir; + uid = uid; + }; + users.groups.readarr = {}; + # Enable and specify VPN namespace to confine service in. systemd.services.readarr.vpnConfinement = mkIf cfg.vpn.enable { enable = true; vpnNamespace = "wg"; }; - # Port mappings vpnNamespaces.wg = mkIf cfg.vpn.enable { portMappings = [ { - from = defaultPort; - to = defaultPort; + from = cfg.port; + to = cfg.port; } ]; }; - services.nginx = mkIf cfg.vpn.enable { enable = true; @@ -103,17 +131,17 @@ in { recommendedOptimisation = true; recommendedGzipSettings = true; - virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { + virtualHosts."127.0.0.1:${builtins.toString cfg.port}" = { listen = [ { addr = "0.0.0.0"; - port = defaultPort; + port = cfg.port; } ]; locations."/" = { recommendedProxySettings = true; proxyWebsockets = true; - proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; + proxyPass = "http://192.168.15.1:${builtins.toString cfg.port}"; }; }; }; diff --git a/nixarr/readarr/readarr-module/default.nix b/nixarr/readarr/readarr-module/default.nix new file mode 100644 index 0000000..3933ec0 --- /dev/null +++ b/nixarr/readarr/readarr-module/default.nix @@ -0,0 +1,93 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.readarr; + servarr = import ./settings-options.nix { inherit lib pkgs; }; +in +{ + options = { + services.readarr = { + enable = lib.mkEnableOption "Readarr, a Usenet/BitTorrent ebook downloader"; + + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/readarr/"; + description = "The directory where Readarr stores its data files."; + }; + + package = lib.mkPackageOption pkgs "readarr" { }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Open ports in the firewall for Readarr + ''; + }; + + settings = servarr.mkServarrSettingsOptions "readarr" 8787; + + environmentFiles = servarr.mkServarrEnvironmentFiles "readarr"; + + user = lib.mkOption { + type = lib.types.str; + default = "readarr"; + description = '' + User account under which Readarr runs. + ''; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "readarr"; + description = '' + Group under which Readarr runs. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.tmpfiles.settings."10-readarr".${cfg.dataDir}.d = { + inherit (cfg) user group; + mode = "0700"; + }; + + systemd.services.readarr = { + description = "Readarr"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = servarr.mkServarrSettingsEnvVars "READARR" cfg.settings; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + EnvironmentFile = cfg.environmentFiles; + ExecStart = "${cfg.package}/bin/Readarr -nobrowser -data='${cfg.dataDir}'"; + Restart = "on-failure"; + }; + }; + + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.settings.server.port ]; + }; + + users.users = lib.mkIf (cfg.user == "readarr") { + readarr = { + description = "Readarr service"; + home = cfg.dataDir; + group = cfg.group; + isSystemUser = true; + }; + }; + + users.groups = lib.mkIf (cfg.group == "readarr") { + readarr = { }; + }; + }; +}