← knowledge.oriz.in

Local dev tunneling — Wrangler + Astro dev + Cloudflare Tunnel

decision decisionsarchitecturedev-toolstunnelingcloudflare-tunnelwranglerastrowebhook-testing

Local dev tunneling — Wrangler + Astro dev + Cloudflare Tunnel

Decision

Local development across the family runs on three substrates, picked by surface:

  1. Wrangler dev — for every Cloudflare Worker (the umbrella api.oriz.in Hono Worker per hono-worker-api-umbrella, the s.oriz.in shortener Worker, the og.oriz.in Satori endpoint). Local mode (wrangler dev) runs in workerd; remote mode (wrangler dev --remote) runs against real Cloudflare infrastructure for KV / R2 / Queues / Durable Objects parity.
  2. Astro dev — for every site (Astro / Vite stack) per cloudflare-pages-for-all-sites. pnpm dev boots the Vite dev server with HMR.
  3. Cloudflare Tunnel (cloudflared) — for exposing localhost:<port> to a public hostname so that webhook senders (Razorpay, GitHub, Bluesky AT Protocol firehose, EmailOctopus) can reach the in-flight Worker / site during development.

ngrok, localtunnel, serveo, and bore — all REJECTED.

User direction 2026-06-20: "Wrangler + Astro dev locked. ALSO add Cloudflare Tunnel (free, CF-native)."

Why

Why not the rejected options

Tool Why rejected
ngrok Free tier rotates hostname every session, forcing webhook re-registration; persistent hostnames require paid plan + card. Anonymous use throttled
localtunnel Hostname is random subdomain on loca.lt, no persistent binding to *.oriz.in; OSS but unmaintained
serveo SSH-tunnel-shaped — no *.oriz.in binding; reliability issues over time
bore / frp / pagekite Self-host or paid past tiny envelope; the family runs only managed serverless
Tailscale Funnel Requires Tailscale-installed receiving party — fits internal collaboration, not public-internet webhooks
GitHub Codespaces port-forward Fits a Codespaces workflow; the family develops locally, not in Codespaces

Implications

Setup (one-time per developer machine)

# Install cloudflared (Windows: winget install cloudflare.cloudflared)
cloudflared tunnel login                       # browser-auth into the CF account
cloudflared tunnel create dev-oriz             # mints a tunnel UUID
cloudflared tunnel route dns dev-oriz dev.oriz.in

Result: dev.oriz.in resolves to the tunnel UUID; whatever cloudflared tunnel run dev-oriz is pointing at receives traffic.

Per-session local dev flow

# Terminal 1 — Worker
cd packages/oriz-api-worker && wrangler dev --port 8787

# Terminal 2 — Site (one of the 11)
cd sites/oriz-blog-site && pnpm dev   # Astro on :3000

# Terminal 3 — public hostname pointing at one of the above
cloudflared tunnel run --url http://localhost:8787 dev-oriz
# now https://dev.oriz.in tunnels to localhost:8787

cloudflared config file at ~/.cloudflared/config.yml:

tunnel: dev-oriz
credentials-file: ~/.cloudflared/<UUID>.json
ingress:
  - hostname: dev.oriz.in
    service: http://localhost:8787
  - service: http_status:404

Webhook testing surfaces

Secrets parity

wrangler dev reads .dev.vars for local secrets; the same keys also exist in Doppler per secrets-management-doppler. doppler run -- wrangler dev keeps the local secrets in sync with Doppler without committing them.

What we don't do

Failure modes documented

Cross-refs