The lab provides the underlay; the mesh builds the overlay. This is the boundary that decides whether the lab is worth having: a scenario that assigns overlay addresses, elects the hub and writes peer configuration certifies its own work — if the mesh's peering is broken, that scenario still comes up green. The most valuable thing the lab can test is exactly the part pre-building would replace. So a scenario declares what a hosting provider and a home router would provide: segments, which machine sits where at which address, what NAT is between them, which ports are forwarded, which machines are detached. It declares nothing about overlay addresses, hubs, peering, names or certificates, all of which become outcomes to observe. The declaration has four parts — segments, machines, place, snapshot — and the two scenario classes differ only in place. That is what makes one a strict subset of the other rather than a fork. Research 004's most important finding becomes a format constraint rather than a footnote: the routable segment must use RFC 5737 documentation space, because the mesh decides public versus private by matching the address, and a private range there makes the hub test as unreachable while the mesh silently never forms. A segment without behind: is routable, and a non-documentation address in it should be refused before anything is raised — ADR 0008 applied to a configuration file, since the failure it prevents has no error at all. Four things left open, including the one that matters most: a lab machine is always privileged, so the user and edge profiles have no scenario that exercises them.
51 lines
2.5 KiB
Markdown
51 lines
2.5 KiB
Markdown
---
|
|
status: active
|
|
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-a-lab-node-is-a-virtual-machine.md, 02-DECISIONS/0031-the-lab-provides-the-underlay.md, 03-DESIGN/01-to-be/02-scenario-declaration.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
|
|
|
|
- Not yet stood up. `incus` is declared in `modules/hal/developer/module.yml` and merged
|
|
(PR #944); the lab itself is unbuilt.
|