5.0 KiB
5.0 KiB
| created | path | project | tags | type | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 2026-05-25 | Sources/Homelab | wireguard-postgres-access |
|
project-plan |
Summary
Stand up a hand-rolled WireGuard hub-and-spoke overlay terminating on herbys-dev, with Postgres (currently serving 5 MCP services) as the first consumer. Tower (Lab/11) connects over the tunnel to access Postgres on herbys-dev (Private/21) without opening a Lab→Private firewall hole. Knot DNS serves *.wg.herbylab.dev for stable hostname access.
Goals
- Tower → herbys-dev Postgres access without VLAN firewall changes
- Future-proof shape: additional peers (other hosts, other services) drop in cleanly
- Knot DNS authoritative for the overlay subdomain from day one
- Manual setup first, Ansible-ize later once the shape is proven
Architecture Decisions
- Topology: Hub-and-spoke. herbys-dev is the hub (services live there); all other peers dial in.
- Termination point: WireGuard interface on the herbys-dev VM host (not inside containers). Services bind to the hub WG IP via Docker port mapping.
- Interface name:
wg-lan - Subnet:
10.99.0.0/24(no collision with10.0.x.xLAN VLANs)- hub (herbys-dev):
10.99.0.1 - tower:
10.99.0.2 - room for future peers
.3+
- hub (herbys-dev):
- Listen port: UDP/51820 on herbys-dev
- Key management: per-host generation; private keys never leave the host; public keys registered with hub
- DNS: Knot serves
wg.herbylab.devzone. Names likedb.wg.herbylab.dev→10.99.0.1,herbys-dev.wg.herbylab.dev→10.99.0.1, etc. - Postgres exposure: Compose
ports:rebinds from localhost to10.99.0.1:5432.pg_hba.confallows10.99.0.0/24.
Why not the alternatives
- Direct VLAN routing: opens Lab→Private firewall hole; any future Lab host can hit Postgres. Tunnel-as-access-control is cleaner.
- Tailscale: works fine and is peer-to-peer on LAN, but adds a third-party control plane for a two-host LAN-local need. WireGuard is already in-kernel.
- Traefik TCP passthrough: wrong layer for L4 forwarding of one port. Traefik stays HTTP(S)-focused.
- SSH tunnel: per-session, dies with the connection. Not viable for always-on MCPs.
Phases
Phase 1 — Hub setup on herbys-dev
- Install
wireguardpackage (Ubuntu repos) - Generate hub keypair (
wg genkey | tee privatekey | wg pubkey > publickey) - Write
/etc/wireguard/wg-lan.confwith[Interface]block (private key, address10.99.0.1/24, listen port 51820) - Open UDP/51820 on herbys-dev firewall + OpenWrt firewall rule allowing tower VLAN → herbys-dev:51820
systemctl enable --now wg-quick@wg-lan- Verify interface up with
wg show
Phase 2 — Tower peer
- Install
wireguardon tower (Endeavour OS) - Generate tower keypair
- Add tower's
[Peer]block to hub config; reload hub - Write tower's
/etc/wireguard/wg-lan.confwith[Interface](tower key,10.99.0.2/24) and[Peer](hub pubkey, endpoint10.0.21.207:51820, AllowedIPs10.99.0.0/24, PersistentKeepalive 25) - Bring tunnel up; verify handshake with
wg show - Ping
10.99.0.1from tower
Phase 3 — Knot DNS records
- Add
wg.herbylab.devzone (or records under existing zone) db.wg.herbylab.dev→10.99.0.1herbys-dev.wg.herbylab.dev→10.99.0.1- Verify resolution from tower via Pi-hole conditional forwarding
Phase 4 — Postgres rebind
- Update Postgres container compose:
ports: - "10.99.0.1:5432:5432" - Verify
listen_addresses = '*'inpostgresql.conf - Add
pg_hba.confrule:host all <user> 10.99.0.0/24 scram-sha-256 - Reload Postgres
- Test connection from tower:
psql -h db.wg.herbylab.dev -U <user> -d <db> - Verify existing 5 MCP services still connect (they're on the host's loopback or docker network — bind change shouldn't affect them, but verify)
Phase 5 — Documentation & follow-ups
- Document peer registration steps for future hosts
- Capture key rotation procedure
- Decide Ansible role shape (extend existing in-progress role)
Open Questions
- Does the Postgres rebind to
10.99.0.1:5432break the 5 existing MCP services? Need to confirm how they currently connect (loopback on host? docker network?). May need to bind to multiple addresses or rethink published port. - Should
wg-lancome up before Docker, so Postgres can bind to it on boot?After=wg-quick@wg-lan.serviceon the docker unit, or reorder via compose.
Future-Proofing Notes
- Subnet has room for ~250 peers; way more than needed
- New peer = one
[Peer]block on hub + one config on new host - Any future service on herbys-dev can bind to
10.99.0.1and inherit the same access model - When Ansible role lands, hub config becomes templated from peer registry
References
- Related:
traefik-deployment(Knot DNS already deployed) - Related:
postgres-consolidation-reflection-layer(the Postgres instance this exposes) - Related:
herbys-dev-setup(host this terminates on)