Mesh networking
The mesh subsystem gives you a flat overlay across all your gateways and any clients you’ve joined. You can use it for remote management (SSH into a Pi at home from a laptop on the other side of the world) or for traffic (use a peer node as your egress).
The Gateway supports two control planes:
- Tailscale — SaaS coordinator, zero setup, free tier. Easy mode.
- Headscale — self-hosted coordinator, fully under your control. The installer can bring it up alongside
gatewayd.
The dataplane in both cases is the same WireGuard, with STUN / DERP relays for NAT traversal.
What it gives you
Section titled “What it gives you”- Peer-to-peer reachability between every node you’ve joined to the mesh, regardless of NAT.
- Subnet routing — advertise your LAN (
192.168.10.0/24) from one gateway and reach it from another. - Exit nodes — route a remote peer’s egress through your gateway (useful for routing a travel laptop through home).
- Hostname discovery — every node has a stable hostname inside the mesh DNS (
*.headscale.lanor*.ts.net). - Per-peer ACLs — Headscale supports Tailscale-style ACL files; rules apply per-source / per-destination.
Headscale, self-hosted
Section titled “Headscale, self-hosted”The full install profile sets up Headscale alongside gatewayd. The bootstrap config:
mesh: enabled: true provider: headscale server_url: "https://mesh.example.invalid:8085" api_key: "REDACTED" auth_key: "REDACTED" namespace: "default" poll_interval: 30 advertise_routes: - "192.168.10.0/24" exit_node: falseThe Headscale instance runs as its own systemd unit; gatewayd only consumes its API.
Tailscale, SaaS
Section titled “Tailscale, SaaS”mesh: enabled: true provider: tailscale auth_key: "tskey-auth-REDACTED" advertise_routes: - "192.168.10.0/24"Pick one provider at startup; switching requires a daemon restart with the new bootstrap config.
Inter-gateway federation vs mesh
Section titled “Inter-gateway federation vs mesh”Two related things:
- Mesh is overlay connectivity. Any device with
tailscale/tailscale upjoins. - Federation is configuration sharing between
gatewaydinstances. It usually runs over a mesh tunnel, but it’s a separate concern: federation is about which config kinds flow between which peers; mesh is about whether boxes can reach each other.
A common deployment: mesh joins five nodes; federation has one node push routing and dns to the other four.
API surface
Section titled “API surface”| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/mesh/status |
Coordinator reachable? Local node state. |
GET |
/api/v1/mesh/config |
Current mesh configuration |
GET |
/api/v1/mesh/peers |
List peers with IP, hostname, RTT, online |
DELETE |
/api/v1/mesh/peers/{id} |
Remove a peer |
POST |
/api/v1/mesh/up |
Bring this node up on the mesh |
POST |
/api/v1/mesh/down |
Take it down |
POST |
/api/v1/mesh/create-key |
Mint a Headscale pre-auth key |
POST |
/api/v1/mesh/register |
Register this node with the coordinator |
GET |
/api/v1/mesh/derp-mode |
DERP-relay mode setting |
Next steps
Section titled “Next steps”When the mesh is up and peers are reachable:
- Build federation on top. Mesh gives you connectivity; federation lets you push/pull selected config kinds across the same tunnel with per-peer allowlists.
- Probe peers from each direction. Symmetric NAT sometimes lets traffic flow one way but not the other — check
gwctl mesh peersfrom both nodes. - Pin DERP if you’re seeing >50 ms RTT to direct-paired peers — a relay can paradoxically be faster than a direct path through a bad route.
- Audit the pre-auth keys you’ve minted. A leaked key joins any device to the mesh; revoke via the coordinator and rotate.
Related
Section titled “Related”- Federation — what runs over the mesh tunnel between gateways.
- Use case: hybrid home lab — home Pi + VPS joined over a self-hosted Headscale mesh.