From 75319256f3b8809e6db7abae41ff8f4b032fcf56 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Thu, 9 Apr 2026 19:00:47 -0400 Subject: [PATCH] lib: add mkCaddyReverseProxy, mkFail2banJail, mkGrafanaAnnotationService, extractArrApiKey --- modules/lib.nix | 103 +++++++++++++++++++++ services/arr/arr-search.nix | 6 +- services/arr/bazarr.nix | 10 +- services/arr/jellyseerr.nix | 8 +- services/arr/prowlarr.nix | 10 +- services/arr/radarr.nix | 10 +- services/arr/recyclarr.nix | 4 +- services/arr/sonarr.nix | 10 +- services/bitmagnet.nix | 10 +- services/bitwarden.nix | 18 +--- services/firefox-syncserver.nix | 10 +- services/gitea.nix | 26 ++---- services/grafana/grafana.nix | 10 +- services/grafana/jellyfin-annotations.nix | 36 ++----- services/grafana/llama-cpp-annotations.nix | 35 ++----- services/immich.nix | 27 ++---- services/llama-cpp.nix | 13 +-- services/matrix/matrix.nix | 8 +- services/ntfy/ntfy.nix | 8 +- services/qbittorrent.nix | 11 ++- services/soulseek.nix | 9 +- services/syncthing.nix | 10 +- services/trilium.nix | 9 +- 23 files changed, 221 insertions(+), 180 deletions(-) diff --git a/modules/lib.nix b/modules/lib.nix index 7e3160c..85d6b92 100644 --- a/modules/lib.nix +++ b/modules/lib.nix @@ -176,5 +176,108 @@ inputs.nixpkgs.lib.extend ( after = [ "${serviceName}-file-perms.service" ]; }; }; + # Creates a Caddy virtualHost with reverse_proxy to a local or VPN-namespaced port. + # Use `subdomain` for ".${domain}" or `domain` for a full custom domain. + # Exactly one of `subdomain` or `domain` must be provided. + mkCaddyReverseProxy = + { + subdomain ? null, + domain ? null, + port, + auth ? false, + vpn ? false, + }: + assert (subdomain != null) != (domain != null); + { config, ... }: + let + vhostDomain = if domain != null then domain else "${subdomain}.${service_configs.https.domain}"; + upstream = + if vpn then + "${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString port}" + else + ":${builtins.toString port}"; + in + { + services.caddy.virtualHosts."${vhostDomain}".extraConfig = lib.concatStringsSep "\n" ( + lib.optional auth "import ${config.age.secrets.caddy_auth.path}" ++ [ "reverse_proxy ${upstream}" ] + ); + }; + + # Creates a fail2ban jail with systemd journal backend. + # Covers the common pattern: journal-based detection, http/https ports, default thresholds. + mkFail2banJail = + { + name, + unitName ? "${name}.service", + failregex, + }: + { ... }: + { + services.fail2ban.jails.${name} = { + enabled = true; + settings = { + backend = "systemd"; + port = "http,https"; + # defaults: maxretry=5, findtime=10m, bantime=10m + }; + filter.Definition = { + inherit failregex; + ignoreregex = ""; + journalmatch = "_SYSTEMD_UNIT=${unitName}"; + }; + }; + }; + + # Creates a hardened Grafana annotation daemon service. + # Provides DynamicUser, sandboxing, state directory, and GRAFANA_URL/STATE_FILE automatically. + mkGrafanaAnnotationService = + { + name, + description, + script, + after ? [ ], + environment ? { }, + loadCredential ? null, + }: + { + systemd.services."${name}-annotations" = { + inherit description; + after = [ + "network.target" + "grafana.service" + ] + ++ after; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.python3}/bin/python3 ${script}"; + Restart = "always"; + RestartSec = "10s"; + DynamicUser = true; + StateDirectory = "${name}-annotations"; + NoNewPrivileges = true; + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + MemoryDenyWriteExecute = true; + } + // lib.optionalAttrs (loadCredential != null) { + LoadCredential = loadCredential; + }; + environment = { + GRAFANA_URL = "http://127.0.0.1:${toString service_configs.ports.private.grafana.port}"; + STATE_FILE = "/var/lib/${name}-annotations/state.json"; + } + // environment; + }; + }; + + # Shell command to extract an API key from an *arr config.xml file. + # Returns a string suitable for $() command substitution in shell scripts. + extractArrApiKey = + configXmlPath: "${lib.getExe pkgs.gnugrep} -oP '(?<=)[^<]+' ${configXmlPath}"; } ) diff --git a/services/arr/arr-search.nix b/services/arr/arr-search.nix index e9af616..81e5867 100644 --- a/services/arr/arr-search.nix +++ b/services/arr/arr-search.nix @@ -1,5 +1,6 @@ { pkgs, + lib, service_configs, ... }: @@ -12,7 +13,6 @@ let curl = "${pkgs.curl}/bin/curl"; jq = "${pkgs.jq}/bin/jq"; - grep = "${pkgs.gnugrep}/bin/grep"; # Max items to search per cycle per category (missing + cutoff) per app maxPerCycle = 5; @@ -20,8 +20,8 @@ let searchScript = pkgs.writeShellScript "arr-search" '' set -euo pipefail - RADARR_KEY=$(${grep} -oP '(?<=)[^<]+' ${radarrConfig}) - SONARR_KEY=$(${grep} -oP '(?<=)[^<]+' ${sonarrConfig}) + RADARR_KEY=$(${lib.extractArrApiKey radarrConfig}) + SONARR_KEY=$(${lib.extractArrApiKey sonarrConfig}) search_radarr() { local endpoint="$1" diff --git a/services/arr/bazarr.nix b/services/arr/bazarr.nix index 1c7e0ad..d31b196 100644 --- a/services/arr/bazarr.nix +++ b/services/arr/bazarr.nix @@ -16,6 +16,11 @@ (lib.serviceFilePerms "bazarr" [ "Z ${service_configs.bazarr.dataDir} 0700 ${config.services.bazarr.user} ${config.services.bazarr.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "bazarr"; + port = service_configs.ports.private.bazarr.port; + auth = true; + }) ]; services.bazarr = { @@ -23,11 +28,6 @@ listenPort = service_configs.ports.private.bazarr.port; }; - services.caddy.virtualHosts."bazarr.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${builtins.toString service_configs.ports.private.bazarr.port} - ''; - users.users.${config.services.bazarr.user}.extraGroups = [ service_configs.media_group ]; diff --git a/services/arr/jellyseerr.nix b/services/arr/jellyseerr.nix index ea0223b..70d44c5 100644 --- a/services/arr/jellyseerr.nix +++ b/services/arr/jellyseerr.nix @@ -13,6 +13,10 @@ (lib.serviceFilePerms "jellyseerr" [ "Z ${service_configs.jellyseerr.configDir} 0700 jellyseerr jellyseerr" ]) + (lib.mkCaddyReverseProxy { + subdomain = "jellyseerr"; + port = service_configs.ports.private.jellyseerr.port; + }) ]; services.jellyseerr = { @@ -36,8 +40,4 @@ users.groups.jellyseerr = { }; - services.caddy.virtualHosts."jellyseerr.${service_configs.https.domain}".extraConfig = '' - # import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${builtins.toString service_configs.ports.private.jellyseerr.port} - ''; } diff --git a/services/arr/prowlarr.nix b/services/arr/prowlarr.nix index 543eb1b..45316ab 100644 --- a/services/arr/prowlarr.nix +++ b/services/arr/prowlarr.nix @@ -14,6 +14,12 @@ (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 = { @@ -51,8 +57,4 @@ ExecStart = lib.mkForce "${lib.getExe pkgs.prowlarr} -nobrowser -data=${service_configs.prowlarr.dataDir}"; }; - services.caddy.virtualHosts."prowlarr.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.private.prowlarr.port} - ''; } diff --git a/services/arr/radarr.nix b/services/arr/radarr.nix index 7a62e52..7a523c3 100644 --- a/services/arr/radarr.nix +++ b/services/arr/radarr.nix @@ -16,6 +16,11 @@ (lib.serviceFilePerms "radarr" [ "Z ${service_configs.radarr.dataDir} 0700 ${config.services.radarr.user} ${config.services.radarr.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "radarr"; + port = service_configs.ports.private.radarr.port; + auth = true; + }) ]; services.radarr = { @@ -25,11 +30,6 @@ settings.update.mechanism = "external"; }; - services.caddy.virtualHosts."radarr.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${builtins.toString service_configs.ports.private.radarr.port} - ''; - users.users.${config.services.radarr.user}.extraGroups = [ service_configs.media_group ]; diff --git a/services/arr/recyclarr.nix b/services/arr/recyclarr.nix index 2e96bcc..7b19cbc 100644 --- a/services/arr/recyclarr.nix +++ b/services/arr/recyclarr.nix @@ -13,8 +13,8 @@ let # Runs as root (via + prefix) after the NixOS module writes config.json. # Extracts API keys from radarr/sonarr config.xml and injects them via jq. injectApiKeys = pkgs.writeShellScript "recyclarr-inject-api-keys" '' - RADARR_KEY=$(${lib.getExe pkgs.gnugrep} -oP '(?<=)[^<]+' ${radarrConfig}) - SONARR_KEY=$(${lib.getExe pkgs.gnugrep} -oP '(?<=)[^<]+' ${sonarrConfig}) + RADARR_KEY=$(${lib.extractArrApiKey radarrConfig}) + SONARR_KEY=$(${lib.extractArrApiKey sonarrConfig}) ${pkgs.jq}/bin/jq \ --arg rk "$RADARR_KEY" \ --arg sk "$SONARR_KEY" \ diff --git a/services/arr/sonarr.nix b/services/arr/sonarr.nix index 44dc196..6200dc3 100644 --- a/services/arr/sonarr.nix +++ b/services/arr/sonarr.nix @@ -16,6 +16,11 @@ (lib.serviceFilePerms "sonarr" [ "Z ${service_configs.sonarr.dataDir} 0700 ${config.services.sonarr.user} ${config.services.sonarr.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "sonarr"; + port = service_configs.ports.private.sonarr.port; + auth = true; + }) ]; systemd.tmpfiles.rules = [ @@ -31,11 +36,6 @@ settings.update.mechanism = "external"; }; - services.caddy.virtualHosts."sonarr.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${builtins.toString service_configs.ports.private.sonarr.port} - ''; - users.users.${config.services.sonarr.user}.extraGroups = [ service_configs.media_group ]; diff --git a/services/bitmagnet.nix b/services/bitmagnet.nix index 9d27503..f59e97a 100644 --- a/services/bitmagnet.nix +++ b/services/bitmagnet.nix @@ -8,6 +8,12 @@ { imports = [ (lib.vpnNamespaceOpenPort service_configs.ports.private.bitmagnet.port "bitmagnet") + (lib.mkCaddyReverseProxy { + subdomain = "bitmagnet"; + port = service_configs.ports.private.bitmagnet.port; + auth = true; + vpn = true; + }) ]; services.bitmagnet = { @@ -24,8 +30,4 @@ }; }; - services.caddy.virtualHosts."bitmagnet.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString service_configs.ports.private.bitmagnet.port} - ''; } diff --git a/services/bitwarden.nix b/services/bitwarden.nix index 18d3f0b..87547a8 100644 --- a/services/bitwarden.nix +++ b/services/bitwarden.nix @@ -13,6 +13,10 @@ (lib.serviceFilePerms "vaultwarden" [ "Z ${service_configs.vaultwarden.path} 0700 vaultwarden vaultwarden" ]) + (lib.mkFail2banJail { + name = "vaultwarden"; + failregex = ''^.*Username or password is incorrect\. Try again\. IP: \..*$''; + }) ]; services.vaultwarden = { @@ -38,18 +42,4 @@ } ''; - # Protect Vaultwarden login from brute force attacks - services.fail2ban.jails.vaultwarden = { - enabled = true; - settings = { - backend = "systemd"; - port = "http,https"; - # defaults: maxretry=5, findtime=10m, bantime=10m - }; - filter.Definition = { - failregex = ''^.*Username or password is incorrect\. Try again\. IP: \..*$''; - ignoreregex = ""; - journalmatch = "_SYSTEMD_UNIT=vaultwarden.service"; - }; - }; } diff --git a/services/firefox-syncserver.nix b/services/firefox-syncserver.nix index d7f31a6..bc0f656 100644 --- a/services/firefox-syncserver.nix +++ b/services/firefox-syncserver.nix @@ -6,6 +6,13 @@ ... }: { + imports = [ + (lib.mkCaddyReverseProxy { + domain = service_configs.firefox_syncserver.domain; + port = service_configs.ports.private.firefox_syncserver.port; + }) + ]; + services.firefox-syncserver = { enable = true; database = { @@ -33,7 +40,4 @@ ]; }; - services.caddy.virtualHosts."${service_configs.firefox_syncserver.domain}".extraConfig = '' - reverse_proxy :${builtins.toString service_configs.ports.private.firefox_syncserver.port} - ''; } diff --git a/services/gitea.nix b/services/gitea.nix index 907abe5..c82fe19 100644 --- a/services/gitea.nix +++ b/services/gitea.nix @@ -11,6 +11,14 @@ (lib.serviceFilePerms "gitea" [ "Z ${config.services.gitea.stateDir} 0700 ${config.services.gitea.user} ${config.services.gitea.group}" ]) + (lib.mkCaddyReverseProxy { + domain = service_configs.gitea.domain; + port = service_configs.ports.private.gitea.port; + }) + (lib.mkFail2banJail { + name = "gitea"; + failregex = "^.*Failed authentication attempt for .* from :.*$"; + }) ]; services.gitea = { @@ -41,10 +49,6 @@ }; }; - services.caddy.virtualHosts."${service_configs.gitea.domain}".extraConfig = '' - reverse_proxy :${builtins.toString config.services.gitea.settings.server.HTTP_PORT} - ''; - services.postgresql = { ensureDatabases = [ config.services.gitea.user ]; ensureUsers = [ @@ -58,18 +62,4 @@ services.openssh.settings.AllowUsers = [ config.services.gitea.user ]; - # Protect Gitea login from brute force attacks - services.fail2ban.jails.gitea = { - enabled = true; - settings = { - backend = "systemd"; - port = "http,https"; - # defaults: maxretry=5, findtime=10m, bantime=10m - }; - filter.Definition = { - failregex = "^.*Failed authentication attempt for .* from :.*$"; - ignoreregex = ""; - journalmatch = "_SYSTEMD_UNIT=gitea.service"; - }; - }; } diff --git a/services/grafana/grafana.nix b/services/grafana/grafana.nix index 3fd0e13..a66b772 100644 --- a/services/grafana/grafana.nix +++ b/services/grafana/grafana.nix @@ -12,6 +12,11 @@ (lib.serviceFilePerms "grafana" [ "Z ${service_configs.grafana.dir} 0700 grafana grafana" ]) + (lib.mkCaddyReverseProxy { + domain = service_configs.grafana.domain; + port = service_configs.ports.private.grafana.port; + auth = true; + }) ]; services.grafana = { @@ -85,11 +90,6 @@ }; }; - services.caddy.virtualHosts."${service_configs.grafana.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${toString service_configs.ports.private.grafana.port} - ''; - services.postgresql = { ensureDatabases = [ "grafana" ]; ensureUsers = [ diff --git a/services/grafana/jellyfin-annotations.nix b/services/grafana/jellyfin-annotations.nix index 0122b48..f04ac50 100644 --- a/services/grafana/jellyfin-annotations.nix +++ b/services/grafana/jellyfin-annotations.nix @@ -1,40 +1,18 @@ { config, - pkgs, service_configs, lib, ... }: -lib.mkIf (config.services.grafana.enable && config.services.jellyfin.enable) { - systemd.services.jellyfin-annotations = { +lib.mkIf (config.services.grafana.enable && config.services.jellyfin.enable) ( + lib.mkGrafanaAnnotationService { + name = "jellyfin"; description = "Jellyfin stream annotation service for Grafana"; - after = [ - "network.target" - "grafana.service" - ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.python3}/bin/python3 ${./jellyfin-annotations.py}"; - Restart = "always"; - RestartSec = "10s"; - LoadCredential = "jellyfin-api-key:${config.age.secrets.jellyfin-api-key.path}"; - DynamicUser = true; - StateDirectory = "jellyfin-annotations"; - NoNewPrivileges = true; - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - ]; - MemoryDenyWriteExecute = true; - }; + script = ./jellyfin-annotations.py; environment = { JELLYFIN_URL = "http://127.0.0.1:${toString service_configs.ports.private.jellyfin.port}"; - GRAFANA_URL = "http://127.0.0.1:${toString service_configs.ports.private.grafana.port}"; - STATE_FILE = "/var/lib/jellyfin-annotations/state.json"; POLL_INTERVAL = "30"; }; - }; -} + loadCredential = "jellyfin-api-key:${config.age.secrets.jellyfin-api-key.path}"; + } +) diff --git a/services/grafana/llama-cpp-annotations.nix b/services/grafana/llama-cpp-annotations.nix index 3e60fe7..f4f6440 100644 --- a/services/grafana/llama-cpp-annotations.nix +++ b/services/grafana/llama-cpp-annotations.nix @@ -1,39 +1,18 @@ { config, - pkgs, service_configs, lib, ... }: -lib.mkIf (config.services.grafana.enable && config.services.llama-cpp.enable) { - systemd.services.llama-cpp-annotations = { +lib.mkIf (config.services.grafana.enable && config.services.llama-cpp.enable) ( + lib.mkGrafanaAnnotationService { + name = "llama-cpp"; description = "LLM request annotation service for Grafana"; - after = [ - "grafana.service" - "llama-cpp.service" - ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.python3}/bin/python3 ${./llama-cpp-annotations.py}"; - Restart = "always"; - RestartSec = "10s"; - DynamicUser = true; - StateDirectory = "llama-cpp-annotations"; - NoNewPrivileges = true; - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - ]; - MemoryDenyWriteExecute = true; - }; + script = ./llama-cpp-annotations.py; + after = [ "llama-cpp.service" ]; environment = { - GRAFANA_URL = "http://127.0.0.1:${toString service_configs.ports.private.grafana.port}"; - STATE_FILE = "/var/lib/llama-cpp-annotations/state.json"; POLL_INTERVAL = "5"; CPU_THRESHOLD = "50"; }; - }; -} + } +) diff --git a/services/immich.nix b/services/immich.nix index c01dafe..d522c58 100644 --- a/services/immich.nix +++ b/services/immich.nix @@ -16,6 +16,15 @@ (lib.serviceFilePerms "immich-server" [ "Z ${config.services.immich.mediaLocation} 0770 ${config.services.immich.user} ${config.services.immich.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "immich"; + port = service_configs.ports.private.immich.port; + }) + (lib.mkFail2banJail { + name = "immich"; + unitName = "immich-server.service"; + failregex = "^.*Failed login attempt for user .* from ip address .*$"; + }) ]; services.immich = { @@ -29,10 +38,6 @@ }; }; - services.caddy.virtualHosts."immich.${service_configs.https.domain}".extraConfig = '' - reverse_proxy :${builtins.toString config.services.immich.port} - ''; - environment.systemPackages = with pkgs; [ immich-go ]; @@ -42,18 +47,4 @@ "render" ]; - # Protect Immich login from brute force attacks - services.fail2ban.jails.immich = { - enabled = true; - settings = { - backend = "systemd"; - port = "http,https"; - # defaults: maxretry=5, findtime=10m, bantime=10m - }; - filter.Definition = { - failregex = "^.*Failed login attempt for user .* from ip address .*$"; - ignoreregex = ""; - journalmatch = "_SYSTEMD_UNIT=immich-server.service"; - }; - }; } diff --git a/services/llama-cpp.nix b/services/llama-cpp.nix index b7470f9..78f931f 100644 --- a/services/llama-cpp.nix +++ b/services/llama-cpp.nix @@ -13,6 +13,13 @@ let modelAlias = lib.removeSuffix ".gguf" (baseNameOf modelUrl); in { + imports = [ + (lib.mkCaddyReverseProxy { + subdomain = "llm"; + port = service_configs.ports.private.llama_cpp.port; + }) + ]; + services.llama-cpp = { enable = true; model = toString ( @@ -94,10 +101,4 @@ in + " ${utils.escapeSystemdExecArgs cfg.extraFlags}" ); - # Auth handled by llama-cpp --api-key-file (Bearer token). - # No caddy_auth — the API key is the auth layer, and caddy_auth's basic - # auth would block Bearer-only clients like oh-my-pi. - services.caddy.virtualHosts."llm.${service_configs.https.domain}".extraConfig = '' - reverse_proxy :${toString config.services.llama-cpp.port} - ''; } diff --git a/services/matrix/matrix.nix b/services/matrix/matrix.nix index c8952d8..fea48c3 100644 --- a/services/matrix/matrix.nix +++ b/services/matrix/matrix.nix @@ -12,6 +12,10 @@ (lib.serviceFilePerms "continuwuity" [ "Z /var/lib/private/continuwuity 0770 ${config.services.matrix-continuwuity.user} ${config.services.matrix-continuwuity.group}" ]) + (lib.mkCaddyReverseProxy { + domain = service_configs.matrix.domain; + port = service_configs.ports.private.matrix.port; + }) ]; services.matrix-continuwuity = { @@ -53,10 +57,6 @@ respond /.well-known/matrix/client `{"m.server":{"base_url":"https://${service_configs.matrix.domain}"},"m.homeserver":{"base_url":"https://${service_configs.matrix.domain}"},"org.matrix.msc3575.proxy":{"base_url":"https://${config.services.matrix-continuwuity.settings.global.server_name}"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://${service_configs.livekit.domain}"}]}` ''; - services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig = '' - reverse_proxy :${builtins.toString service_configs.ports.private.matrix.port} - ''; - # Exact duplicate for federation port services.caddy.virtualHosts."${service_configs.matrix.domain}:${builtins.toString service_configs.ports.public.matrix_federation.port}".extraConfig = config.services.caddy.virtualHosts."${service_configs.matrix.domain}".extraConfig; diff --git a/services/ntfy/ntfy.nix b/services/ntfy/ntfy.nix index ef26330..a9a8a88 100644 --- a/services/ntfy/ntfy.nix +++ b/services/ntfy/ntfy.nix @@ -12,6 +12,10 @@ (lib.serviceFilePerms "ntfy-sh" [ "Z /var/lib/private/ntfy-sh 0700 ${config.services.ntfy-sh.user} ${config.services.ntfy-sh.group}" ]) + (lib.mkCaddyReverseProxy { + domain = service_configs.ntfy.domain; + port = service_configs.ports.private.ntfy.port; + }) ]; services.ntfy-sh = { @@ -27,8 +31,4 @@ }; }; - services.caddy.virtualHosts."${service_configs.ntfy.domain}".extraConfig = '' - reverse_proxy :${builtins.toString service_configs.ports.private.ntfy.port} - ''; - } diff --git a/services/qbittorrent.nix b/services/qbittorrent.nix index 0b12874..666385d 100644 --- a/services/qbittorrent.nix +++ b/services/qbittorrent.nix @@ -27,6 +27,12 @@ in "z ${config.services.qbittorrent.serverConfig.Preferences.Downloads.TempPath} 0700 ${config.services.qbittorrent.user} ${config.services.qbittorrent.group}" "Z ${config.services.qbittorrent.profileDir} 0700 ${config.services.qbittorrent.user} ${config.services.qbittorrent.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "torrent"; + port = service_configs.ports.private.torrent.port; + auth = true; + vpn = true; + }) ]; services.qbittorrent = { @@ -156,11 +162,6 @@ in _: path: "d ${path} 0770 ${config.services.qbittorrent.user} ${service_configs.media_group} -" ) service_configs.torrent.categories; - services.caddy.virtualHosts."torrent.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString config.services.qbittorrent.webuiPort} - ''; - users.users.${config.services.qbittorrent.user}.extraGroups = [ service_configs.media_group ]; diff --git a/services/soulseek.nix b/services/soulseek.nix index f8c4f62..5f93360 100644 --- a/services/soulseek.nix +++ b/services/soulseek.nix @@ -19,6 +19,10 @@ "Z ${service_configs.slskd.downloads} 0750 ${config.services.slskd.user} music" "Z ${service_configs.slskd.incomplete} 0750 ${config.services.slskd.user} music" ]) + (lib.mkCaddyReverseProxy { + subdomain = "soulseek"; + port = service_configs.ports.private.soulseek_web.port; + }) ]; users.groups."music" = { }; @@ -58,11 +62,6 @@ users.users.${config.services.jellyfin.user}.extraGroups = [ "music" ]; users.users.${username}.extraGroups = [ "music" ]; - # doesn't work with auth???? - services.caddy.virtualHosts."soulseek.${service_configs.https.domain}".extraConfig = '' - reverse_proxy :${builtins.toString config.services.slskd.settings.web.port} - ''; - networking.firewall.allowedTCPPorts = [ service_configs.ports.public.soulseek_listen.port ]; diff --git a/services/syncthing.nix b/services/syncthing.nix index 6200737..0166579 100644 --- a/services/syncthing.nix +++ b/services/syncthing.nix @@ -17,6 +17,11 @@ "Z ${service_configs.syncthing.signalBackupDir} 0750 ${config.services.syncthing.user} ${config.services.syncthing.group}" "Z ${service_configs.syncthing.grayjayBackupDir} 0750 ${config.services.syncthing.user} ${config.services.syncthing.group}" ]) + (lib.mkCaddyReverseProxy { + subdomain = "syncthing"; + port = service_configs.ports.private.syncthing_gui.port; + auth = true; + }) ]; services.syncthing = { @@ -49,9 +54,4 @@ ]; }; - services.caddy.virtualHosts."syncthing.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${toString service_configs.ports.private.syncthing_gui.port} - ''; - } diff --git a/services/trilium.nix b/services/trilium.nix index 758154a..8959e32 100644 --- a/services/trilium.nix +++ b/services/trilium.nix @@ -10,6 +10,11 @@ (lib.serviceMountWithZpool "trilium-server" service_configs.zpool_ssds [ (service_configs.services_dir + "/trilium") ]) + (lib.mkCaddyReverseProxy { + subdomain = "notes"; + port = service_configs.ports.private.trilium.port; + auth = true; + }) ]; services.trilium-server = { @@ -19,8 +24,4 @@ dataDir = service_configs.trilium.dataDir; }; - services.caddy.virtualHosts."notes.${service_configs.https.domain}".extraConfig = '' - import ${config.age.secrets.caddy_auth.path} - reverse_proxy :${toString service_configs.ports.private.trilium.port} - ''; }