# 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`.