Files
vibn-frontend/vibn-dev/PREVIEWS.md
mawkone 3160fe2b56 docs(path-b): mark weeks 1-3 shipped; preview routing scoped
- AI_PATH_B_EXECUTION_PLAN.md: Status changed from "proposed" to
  "week 1 shipped", weeks 1-3 checkboxes flipped to  for the parts
  that landed in vibn-frontend@4ba9407 and @41d4d37. Lists what's
  still manual (DNS wildcard, Coolify host image build, Traefik cert).
- vibn-dev/PREVIEWS.md: Architecture for *.preview.vibnai.com
  routing, the deferred Coolify-compose-hot-update piece, and an
  HMR/websocket troubleshooting checklist.
- vibn-dev/setup-on-coolify.sh: One-shot script to build
  vibn-dev:latest on the Coolify host (referenced by the compose
  template's pull_policy: never).

Made-with: Cursor
2026-04-28 13:02:45 -07:00

3.3 KiB

Preview URL routing for vibn-dev

Goal: every dev_server.start returns a URL like https://vite-mark-marketplace-7a3f.preview.vibnai.com that works end-to-end (TLS, HMR, websockets) without the user touching DNS or Coolify config.

Architecture

  Browser
    │  https://<sub>.preview.vibnai.com
    ▼
  Traefik (Coolify-managed)
    │  routes by Host header → matching docker label
    ▼
  vibn-dev container for project X
    │  HOST=0.0.0.0 PORT=3000
    ▼
  Vite / Next dev / etc.

Two pieces have to be true for this to work:

  1. DNS wildcard*.preview.vibnai.com must resolve to the Coolify host's public IP. Set this in Cloudflare / OpenSRS once.
  2. Traefik dynamic router — for each running dev_server, attach docker labels to the vibn-dev container so Traefik picks up the subdomain → port mapping.

DNS step (one-time)

In OpenSRS (or whichever DNS we use for vibnai.com):

*.preview.vibnai.com.  IN A  <coolify-host-ip>

Cert: Traefik will solve a wildcard via DNS-01 against the same DNS provider. Add a DNS provider env to Coolify's Traefik:

# already in our Coolify Traefik config
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=opensrs"

(Traefik supports OpenSRS via OPENSRS_USERNAME + OPENSRS_PASSWORD env vars.)

Traefik labels (per dev_server)

When a dev_server starts on port P with subdomain S, we update the vibn-dev compose file with these labels and re-deploy the service:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.vibn-dev-${S}.rule=Host(`${S}.preview.vibnai.com`)"
  - "traefik.http.routers.vibn-dev-${S}.entrypoints=https"
  - "traefik.http.routers.vibn-dev-${S}.tls=true"
  - "traefik.http.routers.vibn-dev-${S}.tls.certresolver=letsencrypt"
  - "traefik.http.services.vibn-dev-${S}.loadbalancer.server.port=${P}"

What's deferred

The current dev_server.start records the URL and PID but does NOT yet update the Coolify compose to add the Traefik labels — that requires an updateService call against Coolify's API with the revised compose YAML, which round-trips through Coolify's deployment pipeline (~30s). For week 1 we keep dev servers reachable from inside the container (shell.exec curl http://localhost:PORT) so the AI can verify they boot, and we'll wire the Traefik label injection in week 2 once we've decided whether to:

(a) bake the labels into the compose at ensureDevContainer time (one Traefik router per fixed port range, e.g. 3000-3010), OR (b) hot-update the compose on each dev_server.start (more flexible but slower and racier).

Recommendation: (a) — pre-allocate router rules for ports 3000-3010 on container creation. Simpler, faster, no compose churn. Limit dev servers per project to 10.

Troubleshooting

  • "Host header mismatch" → check the dev server is actually binding to 0.0.0.0 (not localhost). Some frameworks default to localhost even with HOST=0.0.0.0 env; pass --host 0.0.0.0 to the cli.
  • HMR websocket fails → Vite needs server.hmr.clientPort: 443 and server.hmr.host: <subdomain>.preview.vibnai.com. Document this in the AI system prompt for week 2.
  • 404 from Traefik → labels didn't apply. Check docker inspect vibn-dev-<projectSlug> and verify the labels are present.