diff --git a/docs/gateway.md b/docs/gateway.md index 2496810f..1c59997a 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -200,21 +200,19 @@ dashboard reach by design — the surface is privileged (approve / deny / destroy) and must not be exposed without a real reverse proxy in front. -## `HIVE_FORGE_URL`: domain via gateway for isolated agents, loopback for shared-netns +## `HIVE_FORGE_URL`: loopback for in-cluster, sub-domain for the operator Agents poll `HIVE_FORGE_URL` for Forgejo notifications + run all -`hive-forge` calls against it. `hive-c0re.nix` sets this based on the -network isolation mode: +`hive-forge` calls against it. `hive-c0re.nix` pins this to +`http://127.0.0.1:` for the in-cluster path: every +agent container shares the host's network namespace, so loopback +reaches the forge container directly with no DNS lookup needed. -- **`network.isolateContainers = true`**: agents run in private netns and - get the bridge dnsmasq as their resolver. `HIVE_FORGE_URL` is set to - `http://` (default `forge.`). Agents resolve - the hostname via dnsmasq → bridge IP, then reach nginx on port 80 (bridge - firewall opens 80+443 when isolation is on). nginx proxies to forgejo — the - same path an operator browser takes, no raw port exposure needed. -- **`network.isolateContainers = false`** (default): agents share the host's - network namespace, so loopback reaches forgejo directly. `HIVE_FORGE_URL` - is `http://127.0.0.1:`. +The sub-domain default (`forge.`) is for **operator +browsers + cross-host clients**, not in-cluster traffic. Using the +sub-domain URL inside agent containers would fail every `hive-forge` +invocation with "Name or service not known" — the agent's nspawn +doesn't have DNS for the external hostname. ## hive-forge container shape diff --git a/docs/network.md b/docs/network.md index e0d2013c..1b74a7e3 100644 --- a/docs/network.md +++ b/docs/network.md @@ -95,11 +95,6 @@ agent containers. interface only. Other interfaces stay closed. The hive resolver isn't an external-facing service. -When `isolateContainers = true`, `allowedTCPPorts` is extended with -`[ 80 443 ]` so isolated agents can reach nginx (gateway container, -shared host netns) for the forge sub-domain, per-agent UI proxies, -and any other HTTP services. - ## Container isolation `services.hyperhive.network.isolateContainers` (default `false`) flips @@ -113,8 +108,6 @@ agent containers from shared host netns to private netns. Set only after | IP forwarding | `boot.kernel.sysctl."net.ipv4.ip_forward" = 1` | | Internet NAT | `networking.nat { enable = true; internalInterfaces = [ bridgeName ]; }` — MASQUERADE on packets leaving via any external NIC | | Loopback DROP | `networking.firewall.extraInputRules` — drops bridge-subnet → `127.0.0.0/8` traffic; defence-in-depth against routing table leaks | -| Gateway access | `networking.firewall.interfaces..allowedTCPPorts = [ 80 443 ]` — lets isolated agents reach nginx on the host (shared netns) | -| Forge URL | `HIVE_FORGE_URL` flips from `http://127.0.0.1:3000` to `http://forge.` — agents resolve via dnsmasq, nginx proxies to forgejo | | c0re signal | `HIVE_NETWORK_ISOLATION=1`, `HIVE_NETWORK_BRIDGE`, `HIVE_NETWORK_SUBNET` in `systemd.services.hive-c0re.environment` | `HIVE_NETWORK_SUBNET` is the host-side bridge IP + prefix (e.g. diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index b98f9b58..7b89f221 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -557,19 +557,12 @@ in HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName; } // lib.optionalAttrs config.services.hyperhive.forge.enable { - # In-cluster forge URL. - # - Isolated (private netns): containers resolve `forge.` via - # the bridge dnsmasq and reach nginx on port 80. No raw forge port - # needed — nginx proxies to forgejo as it does for the operator. - # - Shared netns: host loopback is reachable, use direct port. - # See `docs/gateway.md::HIVE_FORGE_URL`. - HIVE_FORGE_URL = - if - config.services.hyperhive.network.enable && config.services.hyperhive.network.isolateContainers - then - "http://${config.services.hyperhive.forge.domain}" - else - "http://127.0.0.1:${toString config.services.hyperhive.forge.httpPort}"; + # Loopback for in-cluster calls (agents share host netns; + # external `forge.` sub-domain isn't DNS-resolvable + # from inside nspawn). See + # `docs/gateway.md::HIVE_FORGE_URL: loopback for in-cluster, + # sub-domain for the operator`. + HIVE_FORGE_URL = "http://127.0.0.1:${toString config.services.hyperhive.forge.httpPort}"; } // lib.optionalAttrs config.services.hyperhive.matrix.gui.enable { # Availability flags read by the dashboard's `/api/state`. diff --git a/nix/modules/hive-network.nix b/nix/modules/hive-network.nix index 1cce485a..66725bc6 100644 --- a/nix/modules/hive-network.nix +++ b/nix/modules/hive-network.nix @@ -196,18 +196,6 @@ in resolver must be running before isolation is flipped on). ''; } - { - assertion = - !config.services.hyperhive.forge.enable || config.services.hyperhive.gateway.enable; - message = '' - services.hyperhive.network.isolateContainers = true with - services.hyperhive.forge.enable = true requires - services.hyperhive.gateway.enable = true — isolated agents - reach the forge via `http://forge.` which nginx (in - the gateway container) proxies to forgejo. Without the gateway - there is nothing listening on port 80 to serve that hostname. - ''; - } ]; }) @@ -227,14 +215,6 @@ in ip saddr ${cfg.bridgeIp}/${toString cfg.bridgePrefixLength} ip daddr 127.0.0.0/8 drop ''; - # Allow isolated agents to reach the gateway (nginx on the host, shared - # netns). Port 80 covers `http://forge.`, per-agent UI proxies, - # and any other HTTP services the gateway fronts. Port 443 for HTTPS. - networking.firewall.interfaces.${cfg.bridgeName}.allowedTCPPorts = [ - 80 - 443 - ]; - # Tells hive-c0re to pass PRIVATE_NETWORK + bridge settings to each # container. HIVE_NETWORK_SUBNET is host-bridge IP/prefix, not canonical # network address — the Rust side normalises before subnet arithmetic.