--- 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`_