diff --git a/CHANGELOG.md b/CHANGELOG.md index 24ea338..830a25f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Added: - Plex service - Autobrr service +- Sandboxed Jellyseerr module and added expose option Updated: - If `nixarr.enable` is not enabled other services will automatically now diff --git a/nixarr/ddns/default.nix b/nixarr/ddns/default.nix index ca7fb80..bd21ee7 100644 --- a/nixarr/ddns/default.nix +++ b/nixarr/ddns/default.nix @@ -109,7 +109,7 @@ in { }; }; - config = mkIf (nixarr.enable && cfg.enable) { + config = mkIf nixarr.enable { assertions = [ { assertion = cfg.njalla.enable -> cfg.njalla.keysFile != null; diff --git a/nixarr/jellyfin/default.nix b/nixarr/jellyfin/default.nix index e5fe466..a39b8a6 100644 --- a/nixarr/jellyfin/default.nix +++ b/nixarr/jellyfin/default.nix @@ -16,6 +16,8 @@ in { example = true; description = '' Whether or not to enable the Jellyfin service. + + **Conflicting options:** [`nixarr.plex.enable`](#nixarr.plex.enable) ''; }; @@ -104,6 +106,13 @@ in { config = mkIf (nixarr.enable && cfg.enable) { assertions = [ + { + assertion = cfg.enable -> !nixarr.plex.enable; + message = '' + The nixarr.jellyfin.vpn.enable option requires the nixarr.plex.enable + option to NOT be set, but it was. + ''; + } { assertion = cfg.vpn.enable -> nixarr.vpn.enable; message = '' @@ -147,11 +156,11 @@ in { "d '${cfg.stateDir}' 0700 streamer root - -" # Media Dirs - "d '${nixarr.mediaDir}/library' 0775 streamer media - -" - "d '${nixarr.mediaDir}/library/shows' 0775 streamer media - -" - "d '${nixarr.mediaDir}/library/movies' 0775 streamer media - -" - "d '${nixarr.mediaDir}/library/music' 0775 streamer media - -" - "d '${nixarr.mediaDir}/library/books' 0775 streamer media - -" + "d '${nixarr.mediaDir}/library' 0775 streamer media - -" + "d '${nixarr.mediaDir}/library/shows' 0775 streamer media - -" + "d '${nixarr.mediaDir}/library/movies' 0775 streamer media - -" + "d '${nixarr.mediaDir}/library/music' 0775 streamer media - -" + "d '${nixarr.mediaDir}/library/books' 0775 streamer media - -" ]; # Always prioritise Jellyfin IO diff --git a/nixarr/jellyseerr/default.nix b/nixarr/jellyseerr/default.nix index 00b8212..24bcf29 100644 --- a/nixarr/jellyseerr/default.nix +++ b/nixarr/jellyseerr/default.nix @@ -66,9 +66,51 @@ in { description = '' **Required options:** [`nixarr.vpn.enable`](#nixarr.vpn.enable) + **Conflicting options:** [`nixarr.jellyseerr.expose.https.enable`](#nixarr.jellyseerr.expose.https.enable) + Route Jellyseerr traffic through the VPN. ''; }; + + expose = { + https = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + **Required options:** + + - [`nixarr.jellyseerr.expose.https.acmeMail`](#nixarr.jellyseerr.expose.https.acmemail) + - [`nixarr.jellyseerr.expose.https.domainName`](#nixarr.jellyseerr.expose.https.domainname) + + **Conflicting options:** [`nixarr.jellyseerr.vpn.enable`](#nixarr.jellyseerr.vpn.enable) + + Expose the Jellyseerr web service to the internet with https support, + allowing anyone to access it. + + > **Warning:** Do _not_ enable this without setting up Jellyseerr + > authentication through localhost first! + ''; + }; + + upnp.enable = mkEnableOption "UPNP to try to open ports 80 and 443 on your router."; + + domainName = mkOption { + type = types.nullOr types.str; + default = null; + example = "jellyseerr.example.com"; + description = "The domain name to host Jellyseerr on."; + }; + + acmeMail = mkOption { + type = types.nullOr types.str; + default = null; + example = "mail@example.com"; + description = "The ACME mail required for the letsencrypt bot."; + }; + }; + }; }; config = mkIf (nixarr.enable && cfg.enable) { @@ -80,6 +122,28 @@ in { nixarr.vpn.enable option to be set, but it was not. ''; } + { + assertion = !(cfg.vpn.enable && cfg.expose.https.enable); + message = '' + The nixarr.jellyseerr.vpn.enable option conflicts with the + nixarr.jellyseerr.expose.https.enable option. You cannot set both. + ''; + } + { + assertion = + cfg.expose.https.enable + -> ( + (cfg.expose.https.domainName != null) + && (cfg.expose.https.acmeMail != null) + ); + message = '' + The nixarr.jellyseerr.expose.https.enable option requires the + following options to be set, but one of them were not: + + - nixarr.jellyseerr.expose.https.domainName + - nixarr.jellyseerr.expose.https.acmeMail + ''; + } ]; util-nixarr.services.jellyseerr = { @@ -90,6 +154,56 @@ in { configDir = cfg.stateDir; }; + networking.firewall = mkIf cfg.expose.https.enable { + allowedTCPPorts = [80 443]; + }; + + util-nixarr.upnp = mkIf cfg.expose.https.upnp.enable { + enable = true; + openTcpPorts = [80 443]; + }; + + services.nginx = mkMerge [ + (mkIf (cfg.expose.https.enable || cfg.vpn.enable) { + enable = true; + + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + }) + (mkIf cfg.expose.https.enable { + virtualHosts."${builtins.replaceStrings ["\n"] [""] cfg.expose.https.domainName}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:${builtins.toString defaultPort}"; + }; + }; + }) + (mkIf cfg.vpn.enable { + virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { + listen = [ + { + addr = "0.0.0.0"; + port = defaultPort; + } + ]; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; + }; + }; + }) + ]; + + security.acme = mkIf cfg.expose.https.enable { + acceptTerms = true; + defaults.email = cfg.expose.https.acmeMail; + }; + # Enable and specify VPN namespace to confine service in. systemd.services.jellyseerr.vpnConfinement = mkIf cfg.vpn.enable { enable = true; @@ -105,27 +219,5 @@ in { } ]; }; - - services.nginx = mkIf cfg.vpn.enable { - enable = true; - - recommendedTlsSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - - virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { - listen = [ - { - addr = "0.0.0.0"; - port = defaultPort; - } - ]; - locations."/" = { - recommendedProxySettings = true; - proxyWebsockets = true; - proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; - }; - }; - }; }; } diff --git a/nixarr/jellyseerr/jellyseerr-module/default.nix b/nixarr/jellyseerr/jellyseerr-module/default.nix index 8b4d4a4..103131a 100644 --- a/nixarr/jellyseerr/jellyseerr-module/default.nix +++ b/nixarr/jellyseerr/jellyseerr-module/default.nix @@ -1,4 +1,3 @@ -# TODO: Add expose options for this module { config, pkgs, @@ -68,22 +67,22 @@ in { Group = cfg.group; ExecStart = lib.getExe cfg.package; Restart = "on-failure"; - # TODO: These are from nixpkgs, add them back if we add expose options - # ProtectHome = true; - # ProtectSystem = "strict"; - # PrivateTmp = true; - # PrivateDevices = true; - # ProtectHostname = true; - # ProtectClock = true; - # ProtectKernelTunables = true; - # ProtectKernelModules = true; - # ProtectKernelLogs = true; - # ProtectControlGroups = true; - # NoNewPrivileges = true; - # RestrictRealtime = true; - # RestrictSUIDSGID = true; - # RemoveIPC = true; - # PrivateMounts = true; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + NoNewPrivileges = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + ProtectSystem = "strict"; + ReadWritePaths = [ cfg.configDir ]; }; }; diff --git a/nixarr/plex/default.nix b/nixarr/plex/default.nix index 2d7372f..5d5867f 100644 --- a/nixarr/plex/default.nix +++ b/nixarr/plex/default.nix @@ -16,10 +16,12 @@ in { example = true; description = '' Whether or not to enable the Plex service. + + **Conflicting options:** [`nixarr.jellyfin.enable`](#nixarr.jellyfin.enable) ''; }; - package = mkPackageOption pkgs "plexmediaserver" {}; + package = mkPackageOption pkgs "plex" {}; stateDir = mkOption { type = types.path; @@ -104,6 +106,13 @@ in { config = mkIf (nixarr.enable && cfg.enable) { assertions = [ + { + assertion = cfg.enable -> !nixarr.jellyfin.enable; + message = '' + The nixarr.plex.vpn.enable option requires the nixarr.jellyfin.enable + option to NOT be set, but it was. + ''; + } { assertion = cfg.vpn.enable -> nixarr.vpn.enable; message = ''