From 41d3b4074de8154bbdd3a5b611b53de6f5de17f3 Mon Sep 17 00:00:00 2001 From: sjat Date: Sun, 28 Jun 2026 10:00:29 +0200 Subject: [PATCH] design: route TaPPaaS web services through the VPS Split-horizon DNS + public exposure under *.tappaas.makerfloss.eu, reusing the proven mf01 publishing pattern (new wg1 peer, TLS terminates at VPS, plain HTTP over wg1 to TaPPaaS Caddy). TaPPaaS-side config repo left as an open item. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...026-06-28-tappaas-vps-publishing-design.md | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-28-tappaas-vps-publishing-design.md diff --git a/docs/superpowers/specs/2026-06-28-tappaas-vps-publishing-design.md b/docs/superpowers/specs/2026-06-28-tappaas-vps-publishing-design.md new file mode 100644 index 0000000..0b7c39c --- /dev/null +++ b/docs/superpowers/specs/2026-06-28-tappaas-vps-publishing-design.md @@ -0,0 +1,185 @@ +# Design — Routing TaPPaaS web services through the VPS (split-horizon DNS + public exposure) + +**Date:** 2026-06-28 +**Status:** Design approved; implementation not started. +**Scope:** Expose selected TaPPaaS cluster web services publicly via the makerfloss +VPS, with split-horizon DNS so internal clients resolve the same names to a local +address. Reuses the proven **mf01 service-publishing** pattern. + +> **Where this lands.** The VPS-side changes are implemented in `AnsibleBaobabV4` +> (`host_vars/makerfloss.yml`) on its `main` — mirror this design there when +> execution starts (the mf01 analogue lives at +> `AnsibleBaobabV4/docs/superpowers/specs/2026-06-09-mf01-service-publishing-design.md`). +> This copy lives in the troubleshooting workspace because the design spans repos +> and the TaPPaaS-side config repo is still **open** (see Open items). Authoritative +> values stay in the source repos — values quoted here are proposals and can drift. + +## Goals + +1. **Public exposure** of relevant TaPPaaS web services under + `*.tappaas.makerfloss.eu`, so A records can point at the VPS static IP + `88.99.32.236`. +2. **Split-horizon DNS**: internal clients resolve the same hostnames to TaPPaaS + Caddy's *local* IP (no VPS round-trip); external clients resolve to the VPS. +3. **Preserve the isolation requirement** — nothing on the makerspace side egresses + through the VPS or reaches the homelab; the cluster never becomes a general + transit path. + +## Non-goals + +- Moving TLS authority off the VPS for the external path (no SNI passthrough — see + Decisions). +- Day-one internal resolution for the **makerspace LAN** (deferred — depends on the + OrangeMakers router, which is third-party). +- Changing how the existing apex services (`docs`, `slides`, `forgejo`, `mail`, + `discourse`, `snipeit`, `nb`) are published. + +## Decisions (from brainstorming, 2026-06-28) + +| Decision | Choice | Rationale | +|---|---|---| +| Split-horizon scope | Internal view for **both** cluster + makerspace LAN, **phased** | LAN half depends on third-party router; ship cluster first. | +| VPS ↔ TaPPaaS transport | **New `wg1` WireGuard peer** (FLOSSFirewall) | Mirrors mf01; both ends self-owned; static hub-and-spoke. | +| TLS termination (external) | **Terminate at the VPS** | Cert issuance while isolated is the dealbreaker for passthrough; keeps Gandi DNS-write credential on the VPS only; keeps edge routing/middleware. | +| Naming | **Delegated wildcard** `*.tappaas.makerfloss.eu` | One cert + one route; add services with zero VPS change; avoids apex name clash (`forgejo.tappaas...` vs existing `forgejo.makerfloss.eu`). | +| Internal DNS authority | **FLOSSFirewall** (already runs DNS/DHCP), serving the **cluster now** | LAN deferred per phasing. | + +## Architecture & request flows + +**External request (off-site client):** + +``` +browser ─https─▶ .tappaas.makerfloss.eu (public DNS: A *.tappaas → 88.99.32.236) + ─▶ VPS Traefik :443 (wildcard cert *.tappaas.makerfloss.eu via Gandi DNS-01; TLS ends here) + ─▶ plain HTTP inside wg1 ─▶ FLOSSFirewall/Caddy (wg1 IP 10.13.0.9:80) + ─▶ Caddy routes by Host ─▶ TaPPaaS service (srv01/02/03) +``` + +**Internal request (TaPPaaS cluster now; makerspace LAN later):** + +``` +client ─https─▶ .tappaas.makerfloss.eu (INTERNAL DNS: A → Caddy local IP) + ─▶ Caddy :443 (Caddy's own Let's Encrypt cert; TLS ends here, no VPS round-trip) + ─▶ TaPPaaS service +``` + +**Two views, never colliding.** Public DNS (Gandi) points the wildcard at the VPS; +the FLOSSFirewall's internal resolver points the same wildcard at Caddy's local IP. +A client only ever sees the cert for the IP it resolved — the VPS wildcard +externally, Caddy's own cert internally. + +## Components & changes + +### A. VPS — `AnsibleBaobabV4/host_vars/makerfloss.yml` (additive, mirrors mf01) + +1. **wg1 peer** — add FLOSSFirewall to `wireguard_server_peers`, + `allowed_ips: 10.13.0.9/32` (next free; mf01 is `.8` — confirm free before assigning). +2. **Wildcard cert** — add to `traefik_wildcard_sets`: + ```yaml + - main: "tappaas.makerfloss.eu" + sans: ["*.tappaas.makerfloss.eu"] + ``` + The ACME anchor router issues it automatically via Gandi DNS-01. +3. **Catch-all route** — add `tappaas-delegate.yml` to `traefik_extra_dynamic_files`: + ```yaml + http: + routers: + tappaas-wildcard: + rule: 'HostRegexp(`^.+\.tappaas\.makerfloss\.eu$`)' + entryPoints: [websecure] + service: tappaas-backend + tls: {} + services: + tappaas-backend: + loadBalancer: + passHostHeader: true + servers: + - url: "http://10.13.0.9:80" + ``` + Keep the regex **single-quoted** — a YAML error here breaks the whole file provider. +4. **Public DNS** — add `tappaas` and `*.tappaas` A records → `88.99.32.236` in + `gandi_dns_records`. + +Deploy = the three plays from the mf01 runbook: `play_dns.yml`, +`play_containers.yml --limit makerfloss -t traefik`, and the wireguard server play. +**After this, new services need zero VPS change** — exposure is decided at Caddy. + +### B. FLOSSFirewall / Caddy (TaPPaaS side — repo TBD, see Open items) + +1. **WireGuard client** — peer to the VPS hub (`endpoint makerfloss.eu:51820`), + interface IP `10.13.0.9/32`, `AllowedIPs = 10.13.0.0/24` only → **split-tunnel** + (cluster never routes general traffic through the VPS; isolation preserved). +2. **Caddy plain-HTTP backend** — a Host-routed HTTP listener bound on the wg1 + interface (`10.13.0.9:80`) with **HTTPS-redirect OFF**. This is what the VPS + proxies into. Caddy keeps serving `:443` with its own LE certs to internal + clients unchanged. (Direct mirror of mf01's internal Traefik: redirect off, no + ACME on that path.) +3. **Firewall** — allow `tcp/80` **only from `10.13.0.1`** (the VPS) on the wg + interface. + +### C. Internal DNS (FLOSSFirewall's existing DNS) + +- Override/authoritative answer for `*.tappaas.makerfloss.eu` → Caddy's local IP, + served to the **cluster** now. Makerspace LAN deferred. + +### Exposure policy + +A service is public only if Caddy has a Host route for it; the wildcard + catch-all +just carry whatever Caddy publishes. The VPS's existing `internal-only@file` +middleware can gate specific routes that must stay LAN-only despite living under the +public wildcard. + +## Phasing (each phase independently verifiable) + +1. **Tunnel** — bring up FLOSSFirewall as `wg1` peer `10.13.0.9`; verify + `wg show` on the VPS and bidirectional ping `10.13.0.1 ↔ 10.13.0.9`. +2. **Caddy backend** — stand up the plain-HTTP wg-interface listener; from the VPS, + `curl -H 'Host: .tappaas.makerfloss.eu' http://10.13.0.9:80` returns the service. +3. **VPS edge** — add wildcard cert + catch-all route + public DNS; from off-site, + `curl -s https://.tappaas.makerfloss.eu` returns the service with a valid cert. +4. **Internal DNS** — add the internal `*.tappaas` override on the FLOSSFirewall; + from a cluster node, confirm the name resolves to Caddy's local IP and serves + Caddy's own cert (no VPS round-trip). +5. **(Later)** makerspace LAN internal view — conditional-forward + `tappaas.makerfloss.eu` → FLOSSFirewall + a LAN→TaPPaaS firewall path on the + OrangeMakers router. + +## Isolation (hard requirement — how it's preserved) + +- FLOSSFirewall is **split-tunnel** (`AllowedIPs = 10.13.0.0/24`) — the cluster + never egresses through the VPS; nothing on `wg1` reaches the wider makerspace or + homelab. +- VPS→Caddy reachability is firewalled to `tcp/80 from 10.13.0.1` on the wg + interface only. +- The plain-HTTP backend hop is encrypted on the wire (inside WireGuard). +- No public-DNS-write credential ever leaves the VPS — the reason TLS terminates + there rather than via passthrough. + +## Risks / watch-items + +- Caddy must **not** force HTTPS-redirect on the wg-interface listener, or the VPS + hits a redirect loop (the gotcha mf01 solved with redirect off). +- A YAML error in `tappaas-delegate.yml` breaks the entire VPS file provider — + keep the regex single-quoted. +- `10.13.0.9` must be free on `wg1` — confirm before assigning. +- TaPPaaS is currently firewalled off from production and the VPS link isn't up + yet; phase 1 is the prerequisite for everything else. + +## Open items + +- **TaPPaaS-side config repo is undetermined.** Only *docs* were found in + `~/Projects/MakerFLOSS`; the FLOSSFirewall WireGuard / Caddy / internal-DNS + config repo must be identified (or created) before the implementation plan for + section B/C. +- Makerspace LAN internal view (phase 5) depends on OrangeMakers router cooperation. + +## References + +- mf01 pattern (template): `runbooks/publishing-services-mf01.md`; + `AnsibleBaobabV4/docs/superpowers/specs/2026-06-09-mf01-service-publishing-design.md`. +- VPS Traefik / wg1 / Gandi DNS: `AnsibleBaobabV4/host_vars/makerfloss.yml`. +- TaPPaaS overview: `MakerFLOSS/docs/infrastructure/labdesign.md`, + `MakerFLOSS/docs/infrastructure/vps-and-dns.md`, `MakerFLOSS/docs/hardware/srv0[1-3].md`. +- Network map / access paths: `network-map.md`, `access.md`. + +