diff --git a/docs/presentations/2026-06-28-tappaas-vps-publishing.md b/docs/presentations/2026-06-28-tappaas-vps-publishing.md new file mode 100644 index 0000000..b4eaa8c --- /dev/null +++ b/docs/presentations/2026-06-28-tappaas-vps-publishing.md @@ -0,0 +1,170 @@ +--- +marp: true +theme: gaia +class: invert +paginate: true +--- + + + +# Routing TaPPaaS through the VPS + +### Split-horizon DNS · public exposure on a static IP + +MakerFLOSS · June 2026 · _technical review_ + +--- + +## The goal + +Publish selected **TaPPaaS** web services under `*.tappaas.makerfloss.eu`. + +- **Public exposure** — A records point at the VPS static IP `88.99.32.236`, + so the cluster's services are reachable from anywhere. +- **Split-horizon DNS** — the _same_ hostname resolves to a **local** address + for internal clients, so they never round-trip to the VPS. +- **Isolation preserved** — nothing on the makerspace side egresses through + the VPS or reaches the homelab. + +> We are not inventing anything — we clone a pattern already running. + +--- + +## Building block: the proven `mf01` pattern + +`mf01` already publishes `*.mf01.makerfloss.eu` exactly this way, live since +2026-06-09: + +- TLS terminates on the **VPS** (wildcard cert, Gandi DNS-01). +- Plain HTTP rides the **`wg1`** WireGuard tunnel to an internal reverse proxy. +- The internal proxy routes by **Host** to the right container. + +**TaPPaaS = the same shape**, with Caddy as the internal proxy instead of an +internal Traefik. Low risk, known gotchas already solved. + +--- + +## External request flow + +```mermaid +flowchart LR + C["Browser
(off-site)"] -->|"https · *.tappaas
DNS → 88.99.32.236"| T["VPS Traefik :443
wildcard cert
TLS ends here"] + T -->|"plain HTTP
inside wg1"| K["FLOSSFirewall / Caddy
10.13.0.9:80"] + K -->|"route by Host"| S["TaPPaaS service
srv01 / srv02 / srv03"] +``` + +TLS terminates at the VPS; the backend hop is plain HTTP but **encrypted on the +wire inside WireGuard**. + +--- + +## Internal flow — two views, one name + +```mermaid +flowchart TD + N["<svc>.tappaas.makerfloss.eu"] + N -->|"public DNS (Gandi)"| V["VPS 88.99.32.236
VPS wildcard cert"] + N -->|"internal DNS (FLOSSFirewall)"| L["Caddy local IP
Caddy's own LE cert"] +``` + +A client only ever sees the cert for the IP it resolved — **VPS wildcard +externally, Caddy's own cert internally**. The two views never collide. + +--- + + + +## Key decisions + +| Decision | Choice | Why | +|---|---|---| +| Transport | New **`wg1`** WireGuard peer | Mirrors mf01; both ends self-owned; static hub-and-spoke | +| TLS (external) | **Terminate at the VPS** | Cert issuance while isolated kills passthrough; Gandi DNS-write key stays on the VPS; keeps edge routing/middleware | +| Naming | **Wildcard** `*.tappaas.makerfloss.eu` | One cert + one route; add services with zero VPS change; no apex clash (`forgejo.tappaas…` ≠ `forgejo.makerfloss.eu`) | +| Internal DNS | **FLOSSFirewall** (already runs DNS), cluster first | LAN view deferred — depends on third-party router | + +--- + +## Components — VPS side + +All additive in `AnsibleBaobabV4/host_vars/makerfloss.yml`, mirroring mf01: + +1. **wg1 peer** — FLOSSFirewall, `allowed_ips: 10.13.0.9/32`. +2. **Wildcard cert** — add `tappaas.makerfloss.eu` + `*.tappaas` to + `traefik_wildcard_sets` → ACME anchor issues it via Gandi DNS-01. +3. **Catch-all route** — `tappaas-delegate.yml`: + `HostRegexp(...tappaas...)` → `http://10.13.0.9:80`, `passHostHeader: true`. +4. **Public DNS** — `tappaas` + `*.tappaas` A → `88.99.32.236`. + +After this, **new services need zero VPS change** — exposure is decided at Caddy. + +--- + +## Components — TaPPaaS / Caddy side + +1. **WireGuard client** — peer to the VPS hub, interface `10.13.0.9/32`, + `AllowedIPs = 10.13.0.0/24` only → **split-tunnel** (no general egress + through the VPS). +2. **Caddy plain-HTTP backend** — Host-routed listener on the wg interface + (`10.13.0.9:80`), **HTTPS-redirect OFF**. Caddy keeps serving `:443` with its + own certs to internal clients, unchanged. +3. **Firewall** — allow `tcp/80` **only from `10.13.0.1`** (the VPS) on the wg + interface. + +--- + +## Phasing — five verifiable steps + +1. **Tunnel** — FLOSSFirewall up as `wg1` peer; ping `10.13.0.1 ↔ 10.13.0.9`. +2. **Caddy backend** — from the VPS, + `curl -H 'Host: .tappaas.makerfloss.eu' http://10.13.0.9:80`. +3. **VPS edge** — add cert + route + DNS; off-site + `curl https://.tappaas.makerfloss.eu` with a valid cert. +4. **Internal DNS** — add `*.tappaas` override; a cluster node resolves to + Caddy's local IP and gets Caddy's own cert. +5. **(Later)** makerspace LAN view — conditional-forward + firewall pinhole on + the OrangeMakers router. + +--- + +## Isolation — the hard requirement + +- **Split-tunnel** (`AllowedIPs = 10.13.0.0/24`) — the cluster never egresses + through the VPS; nothing on `wg1` reaches the makerspace or homelab. +- VPS→Caddy locked to `tcp/80 from 10.13.0.1` on the wg interface. +- Backend hop encrypted inside WireGuard. +- **No public-DNS-write credential leaves the VPS** — the reason TLS terminates + there, not via passthrough. + +--- + +## Risks & open items + +- **Caddy redirect** — the wg-interface listener must _not_ force HTTPS-redirect, + or the VPS hits a loop (mf01's known gotcha). +- **YAML safety** — a syntax error in `tappaas-delegate.yml` breaks the whole + VPS file provider; keep the regex single-quoted. +- **`10.13.0.9` free?** — confirm before assigning. +- **TaPPaaS config repo TBD** — the FLOSSFirewall/Caddy/DNS config home is not + yet identified. +- **Phase 5** depends on OrangeMakers router cooperation. + +--- + +## Summary & next steps + +- Reuse the **proven mf01 pattern** — terminate TLS at the VPS, proxy over + `wg1` to TaPPaaS Caddy, split-horizon DNS for the internal view. +- VPS side is a small, additive, **zero-new-tech** change. +- **Next:** identify the TaPPaaS config repo, then write the implementation plan + and execute phases 1–4. + +_Design: `MakerFLOSS_Troubleshooting/docs/superpowers/specs/2026-06-28-tappaas-vps-publishing-design.md`_ +