--- status: graduated initiated: 2026-08-22 touches: [03-DESIGN/00-as-is/01-mesh-and-transport.md, 03-DESIGN/01-to-be/01-end-to-end-testing.md] became: - 02-DECISIONS/0016-the-lab.md - 02-DECISIONS/0016-the-lab.md - 02-DECISIONS/0016-the-lab.md - 03-DESIGN/01-to-be/02-scenario-declaration.md - 03-DESIGN/01-to-be/01-end-to-end-testing.md --- # 004 — Reproducing the mesh network in a lab - **Initiated by:** jochen, 2026-08-22 — *"the most difficult part of our VM setup will be the networking part"* - **Areas touched:** `modules/wireguard`, `modules/dnsmasq-app`, `modules/traefik`, `modules/mesh-ca`, `node_accessors`, `nodes.site` / `nodes.underlay_addr`. ## Summary The network is **entirely generated from mesh-DB rows by module hooks**. `install.d` performs no network configuration whatsoever — no WireGuard, no DNS, no firewall. That makes a faithful lab primarily a *data* problem rather than a networking problem, and means the lab exercises the real code path instead of a reimplementation of it. One constraint decides whether the lab works at all: the WireGuard endpoint rule tests the underlay address against an RFC1918 regex to decide reachability. **A simulated public segment addressed from RFC1918 space silently prevents the mesh from forming** — no endpoint is written for the hub, so nothing can ever initiate. The simulated public segment must therefore use TEST-NET-3 (`203.0.113.0/24`). With that one substitution the lab reproduces the production topology exactly, including the case that is hardest to get right: a node that is publicly *named* but sits behind NAT, whose endpoint the hub can only learn from a handshake. Detail in [`analysis.md`](analysis.md). ## Settled **The lab issues its own certificates.** Public names are certified by an ACME server on the lab's wan segment; `.internal` names keep the mesh CA. The lab preserves production's two-CA split rather than collapsing it, because a single-CA lab would hide any bug living in that split. It also makes the router's port forward load-bearing — HTTP-01 must reach the published-but-NATed node on port 80, so a broken forward becomes a reproducible certificate failure instead of a mystery. Requires one change: `caServer` is not set on the reverse proxy today, so it defaults to the public authority's **production** endpoint. It must become configurable, defaulting to production so real nodes are unaffected. ## Open *Closed 2026-08-25.* The lab is stood up. The topology this effort described raises, and the substitution it turned on — a simulated public segment addressed from documentation space rather than RFC1918 — is enforced by the declaration validator before anything is raised rather than left as a thing to remember. The certificate conclusion above is carried by [`01-end-to-end-testing.md`](../../03-DESIGN/01-to-be/01-end-to-end-testing.md), which specifies the lab's own ACME issuer on the public segment. It is **designed and not built** — implementation state is a third axis, and the effort graduates on its conclusions, not on their delivery. One item leaves this effort without a home and is recorded here so it is not lost: the reverse proxy does not set `caServer`, so it defaults to the public authority's production endpoint. That is a fact about what runs today, not about the lab.