Compare commits

...
Author SHA1 Message Date
atlas
23f13d9e71 chore(docs,nix): fix stale 'localhost via shared netns' claims in forge/matrix
Agents in private netns can't reach host loopback directly; they
use forge.<domain> and matrix.<domain> via the gateway. Update four
locations that still claimed direct loopback access:

- hive-forge.nix: module header + openFirewall description
- hive-matrix.nix: openFirewall description
- docs/matrix.md: container design bullet + openFirewall section
2026-07-04 22:54:38 +02:00
atlas
d7bed0052c chore(nix): fix stale 'localhost via shared netns' claim in forge openFirewall doc
Agents in private netns reach the forge at forge.<domain> via the
gateway, not via localhost directly. The conclusion (firewall only
matters for external access) is correct; the mechanism description
was stale from the pre-isolation era.
2026-07-04 22:54:38 +02:00
atlas
03e07c7d37 chore(nix): fix remaining stale shared-netns references in harness-base.nix
- Option doc: 'Default points at the in-host tuwunel (shared netns)'
  → updated to reflect that c0re forwards the gateway URL at runtime
- DNS oneshot comment: 'inert in shared-netns mode' → removed since
  isolation is always on; oneshot always runs
2026-07-04 22:54:38 +02:00
atlas
9067398e3c chore(docs,nix): remove stale shared-netns references from matrix URL docs
Agents run in private netns (always-on isolation) and can't reach
host loopback directly. hive-c0re forwards HIVE_MATRIX_URL set to
`matrix.<domain>` via the gateway. Update two places that still
referenced the removed shared-netns path.
2026-07-04 22:54:38 +02:00
5 changed files with 44 additions and 45 deletions

View file

@ -17,10 +17,9 @@ Same shape as [`gateway.md::hive-forge container shape`](gateway.md):
operator already runs on the host — separate systemd namespace, operator already runs on the host — separate systemd namespace,
separate state dir. separate state dir.
- Container shares the host network namespace - Container shares the host network namespace
(`privateNetwork = false`) so agents reach tuwunel at (`privateNetwork = false`) for state + systemd-unit isolation. Agents
`http://localhost:<httpPort>` without extra plumbing — the reach the homeserver at `matrix.<domain>` via the gateway (agents
nixos-container is here for state + systemd-unit isolation, not run in private netns and can't access host loopback directly).
network isolation.
- Persistent state at - Persistent state at
`/var/lib/nixos-containers/hive-matrix/var/lib/matrix-tuwunel/` `/var/lib/nixos-containers/hive-matrix/var/lib/matrix-tuwunel/`
survives container restart / host reboot. To wipe, destroy the survives container restart / host reboot. To wipe, destroy the
@ -52,9 +51,9 @@ sub-domain from the user-facing identifier.
## Default-closed firewall ## Default-closed firewall
`openFirewall` defaults to `false` (secure-by-default): the `openFirewall` defaults to `false` (secure-by-default): the host
homeserver is reachable from the host + every agent container via reaches the homeserver on loopback, and agent containers reach it
loopback either way (shared netns), so the firewall hole only at `matrix.<domain>` via the gateway — so the firewall hole only
matters for access from *outside* the host. Flip to `true` when matters for access from *outside* the host. Flip to `true` when
announcing the homeserver to other hives or when an external matrix announcing the homeserver to other hives or when an external matrix
client needs to reach the client-server API directly. client needs to reach the client-server API directly.

View file

@ -462,11 +462,11 @@ Validated: must be an `http://` or `https://` URL or the empty string.
**`hyperhive.matrix.url`** — homeserver URL used by **`hyperhive.matrix.url`** — homeserver URL used by
`hive-matrix-daemon` when connecting via the matrix-sdk. Default `hive-matrix-daemon` when connecting via the matrix-sdk. Default
points at the in-host tuwunel (`localhost:8008`), reachable over the (`localhost:8008`) is overridden by hive-c0re at deploy time to the
host loopback in shared-netns mode. Override per-agent when an agent gateway-routed `matrix.<domain>` URL so isolated agents can reach the
should talk to a different homeserver — for example a remote hive's homeserver. Override per-agent when an agent should talk to a
tuwunel reached over a VPN, or an external Matrix server for a different homeserver — for example a remote hive's tuwunel reached
federation-only agent. over a VPN, or an external Matrix server for a federation-only agent.
### Claude Code plugins ### Claude Code plugins

View file

@ -56,8 +56,8 @@ let
in in
{ {
# Private Forgejo in a `hive-forge` nixos-container, shared host # Private Forgejo in a `hive-forge` nixos-container, shared host
# netns so agents reach it on loopback. State at # netns. Agents reach it at `forge.<domain>` via the gateway. State
# `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives # at `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives
# restart. See `docs/gateway.md::hive-forge container shape`. # restart. See `docs/gateway.md::hive-forge container shape`.
# The internal forge is mandatory — it's the canonical store for the # The internal forge is mandatory — it's the canonical store for the
@ -182,13 +182,12 @@ in
example = true; example = true;
description = '' description = ''
Open `httpPort` + `sshPort` in the host firewall. Off by Open `httpPort` + `sshPort` in the host firewall. Off by
default (secure-by-default): the forge is reachable from the default (secure-by-default): agent containers reach the forge
host + every agent container via `localhost` either way at `forge.<domain>` via the gateway (not directly), and the
(shared netns), so the firewall opens only matter for access host reaches it on loopback so the firewall opens only
from outside the host. Flip to `true` when you want the matter for access from outside the host. Flip to `true` when
operator's browser / external git clients to hit the forge you want the operator's browser or external git clients to
directly. (The container shares host netns, so this is the hit the forge directly.
only firewall layer that matters.)
**Breaking change**: this used to default to `true`. If you **Breaking change**: this used to default to `true`. If you
relied on the old default for external reach, add relied on the old default for external reach, add

View file

@ -173,12 +173,12 @@ in
example = true; example = true;
description = '' description = ''
Open `httpPort` in the host firewall. Off by default Open `httpPort` in the host firewall. Off by default
(secure-by-default): the homeserver is reachable from the (secure-by-default): the host reaches the homeserver on
host + every agent container via `localhost` either way loopback, and agent containers reach it at `matrix.<domain>`
(shared netns), so the firewall open only matters for access via the gateway so the firewall open only matters for
from outside the host. Flip to `true` when announcing the access from outside the host. Flip to `true` when announcing
homeserver to other hives or when an external matrix client the homeserver to other hives or when an external matrix
needs to reach the client-server API directly. client needs to reach the client-server API directly.
**Breaking change**: this used to default to `true`. If you **Breaking change**: this used to default to `true`. If you
relied on the old default for external reach, add relied on the old default for external reach, add

View file

@ -510,10 +510,12 @@ in
example = "https://matrix.darkest.space"; example = "https://matrix.darkest.space";
description = '' description = ''
Matrix homeserver URL the agent's `hive-matrix-daemon` connects Matrix homeserver URL the agent's `hive-matrix-daemon` connects
to. Default points at the in-host tuwunel (shared netns). to. At runtime hive-c0re forwards the isolation-aware URL
Override per-agent when an agent should talk to an external (`matrix.<domain>` via the gateway) so isolated agents reach
homeserver instead (e.g. a federation-only setup or a remote the homeserver without crossing host loopback. Override
hive's tuwunel reached via a vpn). per-agent when an agent should talk to an external homeserver
instead (e.g. a federation-only setup or a remote hive's
tuwunel reached via a vpn).
''; '';
}; };
@ -1516,8 +1518,7 @@ in
# for the hive's own zones, so `forge.<domain>` stops resolving. We # for the hive's own zones, so `forge.<domain>` stops resolving. We
# disable resolvconf and tell dhcpcd not to touch resolv.conf (without # disable resolvconf and tell dhcpcd not to touch resolv.conf (without
# disabling dhcpcd itself, so the veth still gets its address); then # disabling dhcpcd itself, so the veth still gets its address); then
# whoever wrote resolv.conf last owns it: the nixos-container host-copy # the hyperhive-isolated-dns oneshot owns resolv.conf. (Same "take
# in shared netns, or the oneshot in isolated mode. (Same "take
# resolvconf out of the loop" approach the matrix container uses.) # resolvconf out of the loop" approach the matrix container uses.)
networking.resolvconf.enable = false; networking.resolvconf.enable = false;
networking.dhcpcd.extraConfig = "nohook resolv.conf"; networking.dhcpcd.extraConfig = "nohook resolv.conf";
@ -1528,11 +1529,11 @@ in
# 127.0.0.53) is unreachable from a private netns and isn't # 127.0.0.53) is unreachable from a private netns and isn't
# authoritative for the hive's own zones (forge.<domain> etc.). The # authoritative for the hive's own zones (forge.<domain> etc.). The
# bridge dnsmasq (gateway IP) is. hive-priv drops the marker # bridge dnsmasq (gateway IP) is. hive-priv drops the marker
# `/etc/hyperhive-bridge-dns` (containing the gateway IP) only when # `/etc/hyperhive-bridge-dns` (containing the gateway IP) since
# isolation is on, so this oneshot is inert in shared-netns mode — the # isolation is always on; the oneshot reads it and rewrites
# same shared container toplevel does the right thing in both modes. # resolv.conf on every boot. Ordered before the first DNS consumer
# Ordered before the first DNS consumer (tea-login) and the network # (tea-login) and the network targets so name resolution works for
# targets so name resolution works for the very first turn. # the very first turn.
systemd.services.hyperhive-isolated-dns = { systemd.services.hyperhive-isolated-dns = {
description = "point resolv.conf at the hive bridge resolver (isolated containers)"; description = "point resolv.conf at the hive bridge resolver (isolated containers)";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
@ -1729,13 +1730,13 @@ in
RUST_LOG = "info"; RUST_LOG = "info";
} }
# Homeserver URL: by default the daemon inherits the host-forwarded # Homeserver URL: by default the daemon inherits the host-forwarded
# HIVE_MATRIX_URL (set isolation-aware by hive-c0re: `matrix.<domain>` # HIVE_MATRIX_URL (set by hive-c0re to `matrix.<domain>` via the
# via the gateway under private-netns isolation, loopback otherwise), # gateway, since agents run in private netns and can't reach host
# falling back to the daemon's built-in localhost default if the # loopback directly), falling back to the daemon's built-in
# forward is absent. A per-agent `hyperhive.matrix.url` override # localhost default if the forward is absent. A per-agent
# (non-default) is set unit-level so it wins over the forwarded value; # `hyperhive.matrix.url` override (non-default) is set unit-level
# at the default we deliberately DON'T set it so the forwarded # so it wins over the forwarded value; at the default we
# isolation-aware value isn't shadowed. # deliberately DON'T set it so the forwarded value isn't shadowed.
// lib.optionalAttrs (config.hyperhive.matrix.url != matrixUrlDefault) { // lib.optionalAttrs (config.hyperhive.matrix.url != matrixUrlDefault) {
HIVE_MATRIX_URL = config.hyperhive.matrix.url; HIVE_MATRIX_URL = config.hyperhive.matrix.url;
} }