Files
felhom.eu/REPORT.md
T
admin bf099f6a10 docs: SPIKE — offsite-backup connectivity: plain WireGuard wins the ladder (transport decision made)
P0-P7 probe ladder on real ends (demo-felhom PVE host <-> throwaway Hetzner).
Verdict: GO at H1 — plain host-side WG, box-dials-out to a small public endpoint;
Headscale is a separable fleet layer, not a traversal necessity. Line is plain-NAT
(not CGNAT) with zero IPv6 — recorded honestly; CGNAT vantage deferred to Peti VM 110.
Real 2 GiB worst-case PBS backup over the tunnel at the full home uplink, pin intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 22:04:51 +02:00

73 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# felhom.eu — task reports
> **Overwrite** this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in [hub/CHANGELOG.md](hub/CHANGELOG.md); the scripts history lives in [scripts/CHANGELOG.md](scripts/CHANGELOG.md).
---
# REPORT — SPIKE: offsite-backup connectivity (WireGuard, home-NAT traversal) (2026-07-03)
Docs-only run; evidence doc: `documentation/audits/SPIKE-connectivity-wireguard-2026-07-03.md`.
No production code, no Headscale on the real hub, no agent change, no persistent felhom-pve config.
## Verdict
**GO at the lowest rung (H1): plain WireGuard, host-side, box-dials-out to a small public
endpoint.** No coordinator, no relay, no mesh. Headscale (P5: 0.29.2 stood up throwaway) is a
*separable fleet-management layer* — TLS control plane + DB + tailscaled-per-box + Tailscale-hosted
DERP by default — not a traversal necessity for hub-and-spoke backup.
## Probe ladder results (both ends real: demo-felhom PVE host ⟷ throwaway Hetzner CX23)
- **P0** — the operator's line is **plain single-NAT with a fixed public IPv4**
(`37.191.56.193`, catv.fixed.one.hu, AS21334), *not* CGNAT (no 100.64/10 hop; source IP at the
server = egress IP). **Zero IPv6** (no address, no egress, 15-min RA capture: 0 packets).
- **P1 (H0 v6-direct)** — N/A on this line; keep the production endpoint dual-stack anyway.
- **P2 (H1)** — plain WG v4 up on the **first try**; RTT ~3040 ms; **11.4-min fully-idle hold**
(keepalive-only, NAT mapping unmoved, instant ping after); PBS 4.2.2 API through the tunnel with
the **exact-cert pin intact** (`pin.go` model) + negative wrong-pin proof; `:8007` tunnel-only
by firewall (public probe: unreachable).
- **P3** — uplink is the bottleneck: direct 42 Mbit/s up / 200230 down; tunnel upload ~39 Mbit/s
(~5% overhead); PBS TLS benchmark through tunnel **4.94 MB/s = the full uplink**; **real 2 GiB
worst-case (urandom) backup: 4.26 MiB/s sustained, 8 min, zero stalls**. First backup 50100 GB
≈ 36 h (overnight window). Oddity recorded: tunnel *download* (565 Mbit/s, 0 retrans) beat
direct TCP (230, 285 retrans) — UDP encapsulation dodges whatever shapes inbound TCP.
- **P4 (H2)** — outbound UDP fine on **51820 and 443**; no TCP/443 fallback machinery needed.
- **P6** — plain-WG isolation is topological: per-peer `/32` AllowedIPs + forwarding off at the
endpoint; only the PBS port admitted from the WG interface.
- **P7** — hypothesis **refuted with evidence**: kernel WG link creation **succeeds** inside the
unprivileged guest (no `/dev/net/tun` needed — that's confirmed absent and only blocks
tailscaled). Host placement therefore stands on architecture: backups originate host-side, the
tunnel must survive guest death (cloudflared precedent), the guest keeps zero infra creds.
## Architecture recommendation (input to the next task — the production spec)
Host-side agent-managed WG service (cloudflared pattern); per-box keypair minted at install →
pubkey to hub, private key 0600 in agent state dir + **joins the escrowed IdentityBundle** for DR;
endpoint = small public dual-stack VM (€48/mo class), two shapes deferred to the spec: PBS-on-VM
vs **VM-as-rendezvous-relay with DooPlex PBS dialing out too** (both ends outbound-only,
ciphertext-only transit — also solves DooPlex's no-public-UDP). Trust model preserved: box only
dials out; operator-inbound (B) and game-ingress (C) explicitly out of scope.
## Honest caveats
CGNAT traversal is argued from mechanism, **not proven on this line** (it's plain-NAT); second-ISP
confirmation deferred to Peti's VM 110 (currently unreachable). Single ISP/evening; no multi-day
hold; no home-IP-rotation event observed; Headscale assessed server-side only (no tailscaled on
the production host); no restore-direction PBS run.
## Cleanup (verified)
demo-felhom: interface/keys/config/dataset gone (keys **shredded**), iperf3 purged, WG module
unloaded, `/etc/wireguard` untouched-empty, guest probe link deleted — residue-free. Hetzner
throwaway: WG + headscale + PBS torn down, secrets shredded, datastore deleted, box **powered
off** (parked for the Peti follow-up or destruction; jarrs.eu box never touched).
## Repo changes (docs-only)
- NEW `documentation/audits/SPIKE-connectivity-wireguard-2026-07-03.md` (P0P7 verbatim + twelve
§7 answers + recommendation).
- `documentation/runbooks/day0-install.md` — the "LAN-only until Headscale/WireGuard lands"
backlog line now points at the spike (decision made; spec is the remaining gate).
- `CONTEXT.md` — transport decision recorded; next task = production connectivity spec.
- `scripts/CHANGELOG.md` — docs entry.