diff --git a/nixarr/default.nix b/nixarr/default.nix index 52d113e..2b83219 100644 --- a/nixarr/default.nix +++ b/nixarr/default.nix @@ -37,26 +37,22 @@ in { Remember to read the options. ''; - mediaUsers = mkOption { - type = with types; listOf str; - default = []; - description = "Extra users to add the the media group, giving access to the media directory. You probably want to add your own user here."; - }; - mediaDir = mkOption { type = types.path; default = "/data/media"; - description = "The location of the media directory for the services."; + description = '' + The location of the media directory for the services. + ''; }; stateDir = mkOption { type = types.path; default = "/data/.state"; - description = "The location of the state directory for the services."; + description = '' + The location of the state directory for the services. + ''; }; - upnp.enable = mkEnableOption "Enable automatic port forwarding using UPNP."; - vpn = { enable = mkEnableOption ''Enable vpn''; @@ -69,7 +65,7 @@ in { dnsServers = mkOption { type = with types; nullOr (listOf str); default = null; - description = lib.mdDoc '' + description = '' Extra DNS servers for the VPN. If your wg config has a DNS field, then this should not be necessary. ''; @@ -77,12 +73,15 @@ in { }; vpnTestService = { - enable = mkEnableOption "Enable the vpn test service."; + enable = mkEnableOption '' + Enable the vpn test service. Useful for testing DNS leaks or VPN + port forwarding. + ''; port = mkOption { type = types.port; default = 12300; - description = lib.mdDoc '' + description = '' The port that the vpn test service listens to. ''; example = 58403; @@ -93,9 +92,9 @@ in { type = with types; listOf port; default = []; description = lib.mdDoc '' - What TCP ports to allow incoming traffic from. You might need this - if you're port forwarding on your VPN provider and you're setting - up services that is not covered in by this module. + What TCP ports to allow traffic from. You might need this if you're + port forwarding on your VPN provider and you're setting up services + not covered in by this module that uses the VPN. ''; example = [46382 38473]; }; @@ -104,9 +103,9 @@ in { type = with types; listOf port; default = []; description = lib.mdDoc '' - What UDP ports to allow incoming traffic from. You might need this - if you're port forwarding on your VPN provider and you're setting - up services that is not covered in by this module. + What UDP ports to allow traffic from. You might need this if you're + port forwarding on your VPN provider and you're setting up services + not covered in by this module that uses the VPN. ''; example = [46382 38473]; }; @@ -169,7 +168,7 @@ in { systemd.tmpfiles.rules = [ # State dirs - "d '${cfg.stateDir}' 0755 root root - -" + "d '${cfg.stateDir}' 0755 root root - -" "d '${cfg.stateDir}/nixarr' 0755 root root - -" "d '${cfg.stateDir}/nixarr/jellyfin' 0700 jellyfin root - -" "d '${cfg.stateDir}/nixarr/transmission' 0700 transmission root - -" @@ -196,9 +195,7 @@ in { "d '${cfg.mediaDir}/torrents/readarr' 0755 transmission media - -" ]; - kirk.upnp.enable = cfg.upnp.enable; - - kirk.vpnnamespace = { + util.vpnnamespace = { enable = true; accessibleFrom = [ "192.168.1.0/24" diff --git a/nixarr/jellyfin/default.nix b/nixarr/jellyfin/default.nix index b086a28..23787fc 100644 --- a/nixarr/jellyfin/default.nix +++ b/nixarr/jellyfin/default.nix @@ -10,57 +10,68 @@ with lib; let dnsServers = config.lib.vpn.dnsServers; in { options.nixarr.jellyfin = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "enable jellyfin"; - }; + enable = mkEnableOption "Enable the Jellyfin service."; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/jellyfin"; - description = lib.mdDoc "The state directory for jellyfin"; + description = "The state directory for Jellyfin."; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with prowlarr"; - }; + vpn.enable = mkEnableOption '' + Route Jellyfin traffic through the VPN. Requires that `nixarr.vpn` + is configured + ''; - nginx = { - enable = mkEnableOption "Enable nginx for jellyfin"; + expose = { + enable = mkEnableOption '' + Enable nginx for Jellyfin, exposing the web service to the internet. + ''; + + upnp = mkOption { + type = types.bool; + default = false; + description = "Use UPNP to try to open ports 80 and 443 on your router."; + }; domainName = mkOption { type = types.nullOr types.str; default = null; - description = "REQUIRED! The domain name to host jellyfin on."; + description = "REQUIRED! The domain name to host Jellyfin on."; }; acmeMail = mkOption { type = types.nullOr types.str; default = null; - description = "REQUIRED! The ACME mail."; + description = "REQUIRED! The ACME mail required for the letsencrypt bot."; }; }; }; config = - #assert (!(cfg.useVpn && cfg.nginx.enable)) || abort "useVpn not compatible with nginx.enable."; + # TODO: this doesn't work. I don't know why :( + #assert (!(cfg.vpn.enable && cfg.nginx.enable)) || abort "vpn.enable not compatible with nginx.enable."; #assert (cfg.nginx.enable -> (cfg.nginx.domainName != null && cfg.nginx.acmeMail != null)) || abort "Both nginx.domain and nginx.acmeMail needs to be set if nginx.enable is set."; mkIf cfg.enable { - services.jellyfin.enable = cfg.enable; + services.jellyfin = { + enable = cfg.enable; + logDir = "${cfg.stateDir}/log"; + cacheDir = "${cfg.stateDir}/cache"; + dataDir = "${cfg.stateDir}/data"; + configDir = "${cfg.stateDir}/config"; + }; - networking.firewall.allowedTCPPorts = - if cfg.nginx.enable - then [ - 80 # http - 443 # https - ] - else []; + networking.firewall = mkIf cfg.nginx.enable { + allowedTCPPorts = [ 80 443 ]; + }; - services.nginx = mkIf (cfg.nginx.enable || cfg.useVpn) { + util.upnp = mkIf cfg.nginx.upnp.enable { + enable = true; + openTcpPorts = [ 80 443 ]; + }; + + services.nginx = mkIf (cfg.nginx.enable || cfg.vpn.enable) { enable = true; recommendedTlsSettings = true; @@ -77,7 +88,7 @@ in { }; }; - virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = mkIf cfg.useVpn { + virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = mkIf cfg.vpn.enable { listen = [ { addr = "0.0.0.0"; @@ -99,14 +110,14 @@ in { util.vpnnamespace.portMappings = [ ( - mkIf cfg.useVpn { + mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; } ) ]; - containers.jellyfin = mkIf cfg.useVpn { + containers.jellyfin = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -132,8 +143,10 @@ in { services.jellyfin = { enable = true; - group = "jellyfin"; - dataDir = "${cfg.stateDir}"; + logDir = "${cfg.stateDir}/log"; + cacheDir = "${cfg.stateDir}/cache"; + dataDir = "${cfg.stateDir}/data"; + configDir = "${cfg.stateDir}/config"; }; system.stateVersion = "23.11"; diff --git a/nixarr/lidarr/default.nix b/nixarr/lidarr/default.nix index 21262d6..31caa7d 100644 --- a/nixarr/lidarr/default.nix +++ b/nixarr/lidarr/default.nix @@ -9,23 +9,18 @@ with lib; let nixarr = config.nixarr; in { options.nixarr.lidarr = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable lidarr"; - }; + enable = mkEnableOption "Enable the Lidarr service."; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/lidarr"; - description = lib.mdDoc "The state directory for lidarr"; + description = "The state directory for Lidarr"; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with prowlarr"; - }; + vpn.enable = mkEnableOption '' + Route Lidarr traffic through the VPN. Requires that `nixarr.vpn` + is configured + ''; }; config = mkIf cfg.enable { @@ -38,14 +33,14 @@ in { util.vpnnamespace.portMappings = [ ( - mkIf cfg.useVpn { + mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; } ) ]; - containers.lidarr = mkIf cfg.useVpn { + containers.lidarr = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -81,7 +76,7 @@ in { }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true; diff --git a/nixarr/prowlarr/default.nix b/nixarr/prowlarr/default.nix index da234a9..fd8dd36 100644 --- a/nixarr/prowlarr/default.nix +++ b/nixarr/prowlarr/default.nix @@ -12,53 +12,40 @@ with lib; let cfg = config.nixarr.prowlarr; in { options.nixarr.prowlarr = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable prowlarr"; - }; + enable = mkEnableOption "Enable the Prowlarr service."; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/prowlarr"; - description = lib.mdDoc '' - The state directory for prowlarr. Currently doesn't work, except with VPN. - ''; + description = "The state directory for Prowlarr."; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with prowlarr"; - }; + vpn.enable = mkEnableOption '' + Route Prowlarr traffic through the VPN. Requires that `nixarr.vpn` + is configured. + ''; }; config = mkIf cfg.enable { - services.prowlarr = mkIf (!cfg.useVpn) { + util.services.prowlarr = mkIf (!cfg.vpn.enable) { enable = true; - openFirewall = true; + dataDir = cfg.statedir; }; util.vpnnamespace.portMappings = [ ( - mkIf cfg.useVpn { + mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; } ) ]; - containers.prowlarr = mkIf cfg.useVpn { + containers.prowlarr = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; - - bindMounts = { - "/var/lib/prowlarr" = { - hostPath = cfg.stateDir; - isReadOnly = false; - }; - }; + bindMounts."${cfg.statedir}".isReadOnly = false; config = { users.groups.prowlarr = {}; @@ -74,16 +61,16 @@ in { services.resolved.enable = true; networking.nameservers = dnsServers; - services.prowlarr = { + util.services.prowlarr = { enable = true; - openFirewall = true; + dataDir = cfg.stateDir; }; system.stateVersion = "23.11"; }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true; diff --git a/nixarr/prowlarr/module/default.nix b/nixarr/prowlarr/module/default.nix new file mode 100644 index 0000000..4044b20 --- /dev/null +++ b/nixarr/prowlarr/module/default.nix @@ -0,0 +1,74 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.util.services.prowlarr; +in +{ + options = { + util.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") { + sonarr = { + group = cfg.group; + home = cfg.dataDir; + uid = 293; + }; + }; + + users.groups = mkIf (cfg.group == "prowlarr") {}; + }; +} diff --git a/nixarr/radarr/default.nix b/nixarr/radarr/default.nix index 1c11006..313dd5d 100644 --- a/nixarr/radarr/default.nix +++ b/nixarr/radarr/default.nix @@ -12,27 +12,22 @@ with lib; let dnsServers = config.lib.vpn.dnsServers; in { options.nixarr.radarr = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable radarr"; - }; + enable = mkEnableOption "Enable the Radarr service."; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/radarr"; - description = lib.mdDoc "The state directory for radarr"; + description = "The state directory for radarr."; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with radarr"; - }; + vpn.enable = mkEnableOption '' + Route Radarr traffic through the VPN. Requires that `nixarr.vpn` + is configured. + ''; }; config = mkIf cfg.enable { - services.radarr = mkIf (!cfg.useVpn) { + services.radarr = mkIf (!cfg.vpn.enable) { enable = cfg.enable; user = "radarr"; group = "media"; @@ -41,14 +36,14 @@ in { util.vpnnamespace.portMappings = [ ( - mkIf cfg.useVpn { + mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; } ) ]; - containers.radarr = mkIf cfg.useVpn { + containers.radarr = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -84,7 +79,7 @@ in { }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true; diff --git a/nixarr/readarr/default.nix b/nixarr/readarr/default.nix index 9514135..a47be15 100644 --- a/nixarr/readarr/default.nix +++ b/nixarr/readarr/default.nix @@ -9,23 +9,18 @@ with lib; let dnsServers = config.lib.vpn.dnsServers; in { options.nixarr.readarr = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable readarr"; - }; + enable = mkEnableOption "Enable the Readarr service"; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/readarr"; - description = lib.mdDoc "The state directory for readarr"; + description = "The state directory for Readarr"; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with prowlarr"; - }; + vpn.enable = mkEnableOption '' + Route Readarr traffic through the VPN. Requires that `nixarr.vpn` + is configured. + ''; }; config = mkIf cfg.enable { @@ -38,14 +33,14 @@ in { util.vpnnamespace.portMappings = [ ( - mkIf cfg.useVpn { + mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; } ) ]; - containers.readarr = mkIf cfg.useVpn { + containers.readarr = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -81,7 +76,7 @@ in { }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true; diff --git a/nixarr/sonarr/default.nix b/nixarr/sonarr/default.nix index e4239e5..4c0ab86 100644 --- a/nixarr/sonarr/default.nix +++ b/nixarr/sonarr/default.nix @@ -14,24 +14,23 @@ in { enable = mkOption { type = types.bool; default = false; - description = lib.mdDoc "Enable sonarr"; + description = "Enable the Sonarr service."; }; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/sonarr"; - description = lib.mdDoc "The state directory for sonarr"; + description = "The state directory for Sonarr."; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use VPN with sonarr"; - }; + vpn.enable = mkEnableOption '' + Route Readarr traffic through the VPN. Requires that `nixarr.vpn` + is configured. + ''; }; config = mkIf cfg.enable { - services.sonarr = mkIf (!cfg.useVpn) { + services.sonarr = mkIf (!cfg.vpn.enable) { enable = cfg.enable; user = "sonarr"; group = "media"; @@ -39,13 +38,13 @@ in { }; util.vpnnamespace.portMappings = [ - (mkIf cfg.useVpn { + (mkIf cfg.vpn.enable { From = defaultPort; To = defaultPort; }) ]; - containers.sonarr = mkIf cfg.useVpn { + containers.sonarr = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -83,7 +82,7 @@ in { }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true; diff --git a/nixarr/transmission/default.nix b/nixarr/transmission/default.nix index 58a6157..de80f29 100644 --- a/nixarr/transmission/default.nix +++ b/nixarr/transmission/default.nix @@ -11,61 +11,62 @@ with lib; let dnsServers = config.lib.vpn.dnsServers; in { options.nixarr.transmission = { - enable = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Enable transmission"; - }; + enable = mkEnableOption "Enable the Transmission service."; stateDir = mkOption { type = types.path; default = "${nixarr.stateDir}/nixarr/transmission"; - description = lib.mdDoc "The state directory for transmission. Only works with useVpn option."; + description = '' + The state directory for Transmission. + + **BUG**: Only works when the `nixarr.transmission.vpn.enable` option + is set. + ''; }; downloadDir = mkOption { type = types.path; default = "${nixarr.mediaDir}/torrents"; - description = lib.mdDoc '' - The directory for transmission to download to. + description = '' + The directory for Transmission to download to. ''; }; - useVpn = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Run transmission through VPN"; - }; + vpn.enable = mkEnableOption '' + Route Transmission traffic through the VPN. Requires that `nixarr.vpn` + is configured. + ''; - useFlood = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc "Use the flood UI"; - }; + flood.enable = mkEnableOption "Use the flood web-UI"; peerPort = mkOption { type = types.port; default = 50000; - description = "transmission peer traffic port."; + description = "Transmission peer traffic port."; }; uiPort = mkOption { type = types.port; default = 9091; - description = "transmission web-UI port."; + description = "Transmission web-UI port."; }; extraConfig = mkOption { type = types.attrs; default = {}; - description = "Extra settings config for the transmission service."; + description = '' + Extra config settings for the Transmission service. See the + `services.transmission.settings` section of the `configuration.nix` + manual. + ''; }; }; config = mkIf cfg.enable { - services.transmission = mkIf (!cfg.useVpn) { + services.transmission = mkIf (!cfg.vpn.enable) { enable = true; group = "media"; + # TODO: This doesn't work, and it should... #home = cfg.stateDir; webHome = if cfg.useFlood @@ -82,25 +83,32 @@ in { watch-dir-enabled = true; watch-dir = "${nixarr.mediaDir}/torrents/.watch"; + rpc-bind-address = "192.168.15.1"; rpc-port = cfg.uiPort; - rpc-whitelist-enabled = true; + rpc-whitelist-enabled = false; rpc-whitelist = "192.168.15.1,127.0.0.1"; - rpc-authentication-required = true; + rpc-authentication-required = false; blocklist-enabled = true; blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz"; + peer-port = cfg.peerPort; + dht-enabled = true; + pex-enabled = true; + utp-enabled = false; encryption = 1; - utp-enabled = true; port-forwarding-enabled = false; anti-brute-force-enabled = true; anti-brute-force-threshold = 10; + + # 0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace + message-level = 3; } // cfg.extraConfig; }; - util.vpnnamespace = mkIf cfg.useVpn { + util.vpnnamespace = mkIf cfg.vpn.enable { portMappings = [ { From = cfg.uiPort; @@ -111,7 +119,7 @@ in { openTcpPorts = [cfg.peerPort]; }; - containers.transmission = mkIf cfg.useVpn { + containers.transmission = mkIf cfg.vpn.enable { autoStart = true; ephemeral = true; extraFlags = ["--network-namespace-path=/var/run/netns/wg"]; @@ -207,7 +215,7 @@ in { }; }; - services.nginx = mkIf cfg.useVpn { + services.nginx = mkIf cfg.vpn.enable { enable = true; recommendedTlsSettings = true;