diff --git a/config/overlay.nix b/config/overlay.nix index 7bb8db7..141f084 100644 --- a/config/overlay.nix +++ b/config/overlay.nix @@ -56,5 +56,7 @@ _final: prev: { mealie flaresolver deadnix + sillytavern + open-webui ; } diff --git a/docs/constitution.md b/docs/constitution.md index 85cc887..7e8bdc2 100644 --- a/docs/constitution.md +++ b/docs/constitution.md @@ -9,6 +9,7 @@ - Architecture: Flake-based repo using `flake-parts` with inputs for pkgs (stable/unstable), stylix, home-manager, sops-nix, and service overlays. Common modules are composed through `parts/core.nix` and `parts/hosts.nix`. - Module auto-import: `modules/modules.nix` auto-imports `.nix` files under `modules/apps`, `modules/dev`, `modules/scripts`, `modules/servers`, `modules/services`, `modules/shell`, `modules/websites`, and `modules/network`, excluding `librewolf.nix`. Factories live in `modules/factories/` (`mkserver`, `mkscript`), and shared options are in `modules/nix` and `modules/users`. - Hosts and toggles: Host definitions live in `hosts//configuration.nix` with host-specific toggles in `hosts//toggles.nix`. The `my` namespace carries toggles for apps/dev/scripts/services/shell, feature flags like `enableProxy` and `enableContainers`, and per-host `interfaces` and `ips` maps. +- Port assignment: Service ports should live with the service module when the port is intrinsic to a server definition under `modules/servers/`. Miscellaneous or host-specific ports that do not belong to a server module should be centralized in `my.ports` in `modules/modules.nix` and referenced via `config.my.ports.*` (use `toString config.my.ports.*` where a string is required). - Main server and proxies: `my.mainServer` selects the host that should serve traffic by default (default `vps`). Reverse proxies use helpers in `parts/core.nix` (`proxy`, `proxyReverse`, `proxyReverseFix`, `proxyReversePrivate`) and pick IPs from `my.ips` plus the hostName/ip set by `mkserver` options. Nginx defaults to `proxyReverse` for any server with `enableProxy = true` unless `useDefaultProxy = false` or the server is listed in the Fix/Private proxy lists. - Secure hosts and secrets: `my.secureHost` gates SOPS secrets. Secure hosts load secrets from `secrets/*.yaml` and wireguard definitions; non-secure hosts (e.g., `hosts/emacs`) skip secret-dependent services. Default SOPS file is `secrets/secrets.yaml` via `config/base.nix`. Proxy-only services that need private certificates must still define their cert secrets when `enableProxy = true`. diff --git a/hosts/server/configuration.nix b/hosts/server/configuration.nix index 89d13a4..107c085 100644 --- a/hosts/server/configuration.nix +++ b/hosts/server/configuration.nix @@ -25,13 +25,13 @@ in network.firewall.enabledServicePorts = true; network.firewall.additionalPorts = [ 2049 # idk - 8384 # syncthing gui - 22000 # syncthing relay - 3452 # sonarqube - 8448 # synapse ssl - 8265 # tdarr - 5173 # media map - 51412 # qbittorrent + config.my.ports.syncthingGui + config.my.ports.syncthingRelay + config.my.ports.sonarqube + config.my.ports.synapseSsl + config.my.ports.tdarr + config.my.ports.mediaMap + config.my.ports.qbittorrent ]; }; nix.buildMachines = [ diff --git a/hosts/vps/configuration.nix b/hosts/vps/configuration.nix index 1722e87..7fff9d6 100644 --- a/hosts/vps/configuration.nix +++ b/hosts/vps/configuration.nix @@ -10,6 +10,7 @@ let wgInterface = "wg0"; ips = { homeServer = config.my.ips.wg-server; + wgWorkstation = config.my.ips.wg-workstation; wgFriend1 = config.my.ips.wg-friend1; wgGuest1 = config.my.ips.wg-guest1; wgGuest2 = config.my.ips.wg-guest2; @@ -20,15 +21,15 @@ let wgHomelab = config.my.subnets.wg-homelab; }; ports = { - giteaSsh = 22; - ssh = 3456; + giteaSsh = config.my.ports.giteaSsh; + ssh = config.my.ports.ssh; web = [ 80 443 ]; - wg = 51820; - syncthing = 22000; - synapseFederation = 8448; + wg = config.my.ports.wg; + syncthing = config.my.ports.syncthingRelay; + synapseFederation = config.my.ports.synapseSsl; }; portsStr = { giteaSsh = toString ports.giteaSsh; @@ -40,6 +41,10 @@ let jellyfin = toString config.my.servers.jellyfin.port; audiobookshelf = toString config.my.servers.audiobookshelf.port; kavita = toString config.my.servers.kavita.port; + openWebui = toString config.my.ports.openWebui; + sillytavern = toString config.my.ports.sillytavern; + ollama = toString config.my.ports.ollama; + comfyui = toString config.my.ports.comfyui; }; in { @@ -114,6 +119,8 @@ in iifname "${wgInterface}" ip saddr ${subnets.wgGuests} ip daddr ${ips.homeServer}/32 icmp type echo-request accept iifname "${wgInterface}" ip saddr ${subnets.wgHomelab} ip daddr ${ips.homeServer}/32 accept + iifname "${wgInterface}" ip saddr ${subnets.wgHomelab} ip daddr ${ips.wgWorkstation}/32 tcp dport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept + iifname "${wgInterface}" ip saddr ${ips.wgWorkstation}/32 ip daddr ${subnets.wgHomelab} tcp sport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept iifname "${wgInterface}" ip saddr ${subnets.wgFriends} oifname "${externalInterface}" accept iifname "${wgInterface}" ip saddr ${subnets.wgGuests} oifname "${externalInterface}" accept diff --git a/hosts/workstation/configuration.nix b/hosts/workstation/configuration.nix index 9bac09e..4358f85 100644 --- a/hosts/workstation/configuration.nix +++ b/hosts/workstation/configuration.nix @@ -1,12 +1,12 @@ { pkgs, config, + lib, inputs, ... }: let shellType = config.my.shell.type; - comfyuiPort = 8188; krita-thumbnailer = pkgs.writeTextFile { name = "krita-thumbnailer"; destination = "/share/thumbnailers/kra.thumbnailer"; @@ -38,6 +38,9 @@ in "bearded_dragonn" ]; }; + sops.secrets."workstation/private" = lib.mkIf config.my.secureHost { + sopsFile = ../../secrets/wireguard.yaml; + }; home-manager.users.jawz.programs = { vscode = { enable = true; @@ -57,8 +60,8 @@ in hostName = "workstation"; firewall = { allowedTCPPorts = [ - 6674 # ns-usbloader - 8384 # syncthing + config.my.ports.nsUsbloader + config.my.ports.syncthingGui ]; allowedTCPPortRanges = [ { @@ -70,7 +73,31 @@ in config.services.ollama.port config.services.open-webui.port config.services.sillytavern.port - comfyuiPort + config.my.ports.comfyui + ]; + }; + nftables.tables.wg-local-redirect = { + family = "ip"; + content = '' + chain prerouting { + type nat hook prerouting priority dstnat; + iifname "wg0" ip daddr ${config.my.ips.wg-workstation}/32 tcp dport ${toString config.my.ports.sillytavern} redirect to :${toString config.my.ports.sillytavern} + } + ''; + }; + wireguard.interfaces.wg0 = lib.mkIf config.my.secureHost { + ips = [ "${config.my.ips.wg-workstation}/32" ]; + privateKeyFile = config.sops.secrets."workstation/private".path; + peers = [ + { + publicKey = "dFbiSekBwnZomarcS31o5+w6imHjMPNCipkfc2fZ3GY="; + endpoint = "${config.my.ips.vps}:51820"; + persistentKeepalive = 25; + allowedIPs = [ + "${config.my.ips.wg-vps}/32" + config.my.subnets.wg-homelab + ]; + } ]; }; }; @@ -141,7 +168,7 @@ in flatpak.enable = true; open-webui = { enable = true; - port = 2345; + port = config.my.ports.openWebui; host = config.my.ips.wg-workstation; }; scx = { @@ -162,13 +189,14 @@ in models = "/srv/ai/ollama"; user = "ollama"; group = "ai"; + port = config.my.ports.ollama; host = config.my.ips.wg-workstation; }; sillytavern = { enable = true; + port = config.my.ports.sillytavern; group = "ai"; - listen = true; - port = 9324; + whitelist = true; listenAddressIPv4 = config.my.ips.wg-workstation; }; }; diff --git a/modules/modules.nix b/modules/modules.nix index 5477d65..7252998 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -119,6 +119,27 @@ in default = "stunner6399@gmail.com"; description = "localhost smtp email"; }; + ports = lib.mkOption { + type = lib.types.attrsOf lib.types.port; + default = { + comfyui = 8188; + giteaSsh = 22; + mediaMap = 5173; + nsUsbloader = 6674; + ollama = 11434; + openWebui = 2345; + qbittorrent = 51412; + sillytavern = 9324; + sonarqube = 3452; + synapseSsl = 8448; + syncthingGui = 8384; + syncthingRelay = 22000; + tdarr = 8265; + wg = 51820; + ssh = 3456; + }; + description = "Common port assignments for local services and firewall rules."; + }; email = lib.mkOption { type = lib.types.str; default = "danilo.reyes.251@proton.me";