diff --git a/Session_Summaries/2026-03-22_Hosted-IDE-Traefik-Wildcard.md b/Session_Summaries/2026-03-22_Hosted-IDE-Traefik-Wildcard.md new file mode 100644 index 0000000..cd11385 --- /dev/null +++ b/Session_Summaries/2026-03-22_Hosted-IDE-Traefik-Wildcard.md @@ -0,0 +1,107 @@ +# 2026-03-22 – Hosted Dev IDE via Traefik Wildcard + +## Summary + +Long session. Explored multiple approaches to masking the raw API IP in the +IDE browser URL. Ended with the correct architecture working and curl-verified. + +--- + +## Architecture Decision + +Rejected: Traefik direct routing to container (removes API auth boundary, insecure) +Rejected: Caddy on API host (HSTS/HTTPS issues with zerolaghub.dev domain) +Chosen: Traefik on `zlh-zpack-proxy` → API → container + +This is correct because: +- Traefik already handles TLS for the platform +- API remains the auth and proxy boundary +- No per-container DNS or routing side effects needed +- Clean hostname with HTTPS without purchasing a cert + +--- + +## What Was Built + +### Traefik wildcard TLS + +- `zpackv2` certResolver already configured with Cloudflare DNS-01 challenge +- Stale `_acme-challenge` TXT records in Cloudflare blocked initial cert issuance — deleted manually +- Wildcard cert `*.zerolaghub.dev` issued successfully via Let's Encrypt + +### Traefik dynamic config + +```yaml +http: + routers: + dev-ide: + rule: "HostRegexp(`dev-{vmid:[0-9]+}.zerolaghub.dev`)" + entryPoints: + - websecure + service: dev-ide-api + tls: + certResolver: zpackv2 + domains: + - main: "zerolaghub.dev" + sans: + - "*.zerolaghub.dev" + services: + dev-ide-api: + loadBalancer: + passHostHeader: true + servers: + - url: "http://10.60.0.245:4000" +``` + +`passHostHeader: true` is critical — preserves `dev-6070.zerolaghub.dev` +through to the API so `handleHostedProxy` can extract the vmid. + +### API devProxy.js + +`handleHostedProxy` added — extracts vmid from `Host` header, validates +token, sets cookie, proxies to container. This was the missing piece that +caused 404s until the code was deployed. + +`.env` aligned: +- `DEV_IDE_RETURN_HOSTED_URL=true` +- `DEV_IDE_HOST_SUFFIX=zerolaghub.dev` +- `DEV_IDE_PUBLIC_SCHEME=https` + +--- + +## Curl-Verified Response Chain + +``` +GET https://dev-6070.zerolaghub.dev/?token= + → 302 + Set-Cookie: zlh_dev_ide_token + +GET https://dev-6070.zerolaghub.dev/ (with cookie) + → 302 → /?folder=/home/dev/workspace + +GET https://dev-6070.zerolaghub.dev/?folder=/home/dev/workspace + → 200 (code-server HTML) +``` + +Full chain confirmed: Browser → Traefik → API → container:6000 + +--- + +## Key Lessons + +- ERR_CONNECTION_CLOSED from browser (but curl works) = H2 mismatch or wrong + target. In this case it was the API not running the new code (404), not H2. +- `passHostHeader: true` in Traefik is the equivalent of Caddy's + `header_up Host {host}` — without it Express resolves relative redirects + against the internal IP, leaking it to the browser. +- Wildcard certs require DNS-01 challenge — stale TXT records in Cloudflare + will block issuance silently. Check and clear them first. +- Traefik and the API are on different subnets (10.70.x vs 10.60.x) — always + verify cross-subnet reachability with curl before debugging proxy config. + +--- + +## Remaining + +- Browser validation (curl is confirmed, browser WebSocket not yet tested) +- Portal "Open IDE" button confirmation under hosted flow +- Legacy `/__ide/:id` compatibility cleanup once browser is confirmed