wiki-vault/Sources/Homelab/wireguard-postgres-access.md

5.0 KiB

created path project tags type
2026-05-25 Sources/Homelab wireguard-postgres-access
wireguard
postgres
networking
knot
homelab
herbys-dev
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 with 10.0.x.x LAN VLANs)
    • hub (herbys-dev): 10.99.0.1
    • tower: 10.99.0.2
    • room for future peers .3+
  • 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.dev zone. Names like db.wg.herbylab.dev10.99.0.1, herbys-dev.wg.herbylab.dev10.99.0.1, etc.
  • Postgres exposure: Compose ports: rebinds from localhost to 10.99.0.1:5432. pg_hba.conf allows 10.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 wireguard package (Ubuntu repos)
  • Generate hub keypair (wg genkey | tee privatekey | wg pubkey > publickey)
  • Write /etc/wireguard/wg-lan.conf with [Interface] block (private key, address 10.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 wireguard on tower (Endeavour OS)
  • Generate tower keypair
  • Add tower's [Peer] block to hub config; reload hub
  • Write tower's /etc/wireguard/wg-lan.conf with [Interface] (tower key, 10.99.0.2/24) and [Peer] (hub pubkey, endpoint 10.0.21.207:51820, AllowedIPs 10.99.0.0/24, PersistentKeepalive 25)
  • Bring tunnel up; verify handshake with wg show
  • Ping 10.99.0.1 from tower

Phase 3 — Knot DNS records

  • Add wg.herbylab.dev zone (or records under existing zone)
  • db.wg.herbylab.dev10.99.0.1
  • herbys-dev.wg.herbylab.dev10.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 = '*' in postgresql.conf
  • Add pg_hba.conf rule: 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:5432 break 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-lan come up before Docker, so Postgres can bind to it on boot? After=wg-quick@wg-lan.service on 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.1 and 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)