From 7f08a6f788976b6625a9c540eec668c272617f78 Mon Sep 17 00:00:00 2001 From: Richie Cahill Date: Tue, 25 Aug 2026 22:09:44 -0400 Subject: [PATCH] feat(portal): move edge proxy services from Jeeves - move HAProxy and ACME certificate management to Portal - route application backends to Jeeves over Tailscale - restrict Jeeves backend ports to the Tailscale interface - expose Gems for remote proxy access --- common/optional/tailscale.nix | 2 -- systems/jeeves/networking.nix | 9 +++++++++ systems/jeeves/services/gems.nix | 2 +- systems/jeeves/services/gitea.nix | 1 - systems/jeeves/services/jellyfin.nix | 2 +- systems/jeeves/services/nix_serve.nix | 2 +- systems/jeeves/web_services/default.nix | 9 --------- .../web_services => portal-1/haproxy}/acme.nix | 13 +++++-------- .../haproxy.nix => portal-1/haproxy/default.nix} | 3 +++ .../haproxy}/haproxy.cfg | 16 ++++++++-------- .../web_services => portal-1/haproxy}/robots.txt | 0 11 files changed, 28 insertions(+), 31 deletions(-) delete mode 100644 systems/jeeves/web_services/default.nix rename systems/{jeeves/web_services => portal-1/haproxy}/acme.nix (77%) rename systems/{jeeves/web_services/haproxy.nix => portal-1/haproxy/default.nix} (88%) rename systems/{jeeves/web_services => portal-1/haproxy}/haproxy.cfg (96%) rename systems/{jeeves/web_services => portal-1/haproxy}/robots.txt (100%) diff --git a/common/optional/tailscale.nix b/common/optional/tailscale.nix index 3242c64..f99f500 100644 --- a/common/optional/tailscale.nix +++ b/common/optional/tailscale.nix @@ -4,8 +4,6 @@ ... }: { - networking.firewall.trustedInterfaces = [ "tailscale0" ]; - nix.settings = { trusted-substituters = [ "http://jeeves:5000" ]; substituters = [ "http://jeeves:5000/?priority=1&want-mass-query=true" ]; diff --git a/systems/jeeves/networking.nix b/systems/jeeves/networking.nix index 9be9867..f87c1cf 100644 --- a/systems/jeeves/networking.nix +++ b/systems/jeeves/networking.nix @@ -17,6 +17,15 @@ allowedTCPPorts = [ ]; allowedUDPPorts = [ ]; }; + interfaces.tailscale0.allowedTCPPorts = [ + 5000 # Nix binary cache + 6443 # Gitea HTTP + 8000 # Audiobookshelf + 8001 # Norn Sight + 8002 # Gems + 8091 # Share + 8096 # Jellyfin HTTP + ]; allowedTCPPorts = [ 8070 ]; diff --git a/systems/jeeves/services/gems.nix b/systems/jeeves/services/gems.nix index 1f52e60..9164d1e 100644 --- a/systems/jeeves/services/gems.nix +++ b/systems/jeeves/services/gems.nix @@ -36,7 +36,7 @@ in Type = "simple"; User = "gems"; Group = "gems"; - ExecStart = "${pkgs.my_python}/bin/python -m python.gems.main --host 127.0.0.1 --port 8002"; + ExecStart = "${pkgs.my_python}/bin/python -m python.gems.main --host 0.0.0.0 --port 8002"; Restart = "on-failure"; RestartSec = "5s"; StandardOutput = "journal"; diff --git a/systems/jeeves/services/gitea.nix b/systems/jeeves/services/gitea.nix index 2ea98c4..988da6f 100644 --- a/systems/jeeves/services/gitea.nix +++ b/systems/jeeves/services/gitea.nix @@ -3,7 +3,6 @@ let in { networking.firewall.allowedTCPPorts = [ - 6443 2223 ]; diff --git a/systems/jeeves/services/jellyfin.nix b/systems/jeeves/services/jellyfin.nix index 0044e04..eb8c696 100644 --- a/systems/jeeves/services/jellyfin.nix +++ b/systems/jeeves/services/jellyfin.nix @@ -4,7 +4,7 @@ in { services.jellyfin = { enable = true; - openFirewall = true; + openFirewall = false; dataDir = "${vars.services}/jellyfin"; cacheDir = "${vars.services}/jellyfin/cache"; }; diff --git a/systems/jeeves/services/nix_serve.nix b/systems/jeeves/services/nix_serve.nix index d0811b1..6fdc67a 100644 --- a/systems/jeeves/services/nix_serve.nix +++ b/systems/jeeves/services/nix_serve.nix @@ -7,6 +7,6 @@ in package = pkgs.nix-serve-ng; enable = true; secretKeyFile = "${vars.secrets}/services/nix-cache/cache-priv-key.pem"; - openFirewall = true; + openFirewall = false; }; } diff --git a/systems/jeeves/web_services/default.nix b/systems/jeeves/web_services/default.nix deleted file mode 100644 index 1133fcb..0000000 --- a/systems/jeeves/web_services/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ lib, ... }: -{ - imports = - let - files = builtins.attrNames (builtins.readDir ./.); - nixFiles = builtins.filter (name: lib.hasSuffix ".nix" name && name != "default.nix") files; - in - map (file: ./. + "/${file}") nixFiles; -} diff --git a/systems/jeeves/web_services/acme.nix b/systems/portal-1/haproxy/acme.nix similarity index 77% rename from systems/jeeves/web_services/acme.nix rename to systems/portal-1/haproxy/acme.nix index eede8f2..e5a42ac 100644 --- a/systems/jeeves/web_services/acme.nix +++ b/systems/portal-1/haproxy/acme.nix @@ -32,15 +32,12 @@ let ++ map (domain: "acme-${domain}.service") extraDomains; in { - users.users.haproxy.extraGroups = [ "acme" ]; - security.acme = { acceptTerms = true; defaults.email = "Richie@tmmworkshop.com"; certs = builtins.listToAttrs ((map makeCert domains) ++ (map makeExtraCert extraDomains)); }; - # Minimal nginx to serve ACME HTTP-01 challenge files for HAProxy services.nginx = { enable = true; virtualHosts."acme-challenge" = { @@ -56,18 +53,18 @@ in }; }; - # Ensure the challenge directory exists with correct permissions systemd.tmpfiles.rules = [ "d /var/lib/acme/.challenges 0750 acme acme - -" "d /var/lib/acme/.challenges/.well-known 0750 acme acme - -" "d /var/lib/acme/.challenges/.well-known/acme-challenge 0750 acme acme - -" ]; - users.users.nginx.extraGroups = [ "acme" ]; + users.users = { + haproxy.extraGroups = [ "acme" ]; + nginx.extraGroups = [ "acme" ]; + }; - # HAProxy needs certs to exist before it can bind :443. - # NixOS's acme module generates self-signed placeholders on first boot - # via acme-.service — just make HAProxy wait for them. + # HAProxy needs the initial certificates before it can bind to port 443. systemd.services.haproxy = { after = acmeServices; wants = acmeServices; diff --git a/systems/jeeves/web_services/haproxy.nix b/systems/portal-1/haproxy/default.nix similarity index 88% rename from systems/jeeves/web_services/haproxy.nix rename to systems/portal-1/haproxy/default.nix index 47c7c1f..ff8ded6 100644 --- a/systems/jeeves/web_services/haproxy.nix +++ b/systems/portal-1/haproxy/default.nix @@ -1,4 +1,7 @@ +{ ... }: { + imports = [ ./acme.nix ]; + networking.firewall.allowedTCPPorts = [ 80 443 diff --git a/systems/jeeves/web_services/haproxy.cfg b/systems/portal-1/haproxy/haproxy.cfg similarity index 96% rename from systems/jeeves/web_services/haproxy.cfg rename to systems/portal-1/haproxy/haproxy.cfg index 2eefc63..8edd318 100644 --- a/systems/jeeves/web_services/haproxy.cfg +++ b/systems/portal-1/haproxy/haproxy.cfg @@ -120,35 +120,35 @@ backend st_gems_join backend acme_challenge mode http - server acme 127.0.0.1:8402 + server acme jeeves:8402 backend audiobookshelf_nodes mode http - server server 127.0.0.1:8000 + server server jeeves:8000 backend cache_nodes mode http - server server 127.0.0.1:5000 + server server jeeves:5000 backend jellyfin mode http option forwardfor - server jellyfin 127.0.0.1:8096 + server jellyfin jeeves:8096 backend share_nodes mode http - server server 127.0.0.1:8091 + server server jeeves:8091 backend gitea mode http - server server 127.0.0.1:6443 + server server jeeves:6443 backend gems mode http option forwardfor timeout server 1h - server gems 127.0.0.1:8002 + server gems jeeves:8002 backend norn_sight mode http - server server 127.0.0.1:8001 + server server jeeves:8001 diff --git a/systems/jeeves/web_services/robots.txt b/systems/portal-1/haproxy/robots.txt similarity index 100% rename from systems/jeeves/web_services/robots.txt rename to systems/portal-1/haproxy/robots.txt