Skip to content

Automatic Cloudflare quick tunnel for devspace serve + styled startup UI#16

Open
prestonlogan wants to merge 1 commit into
Waishnav:mainfrom
prestonlogan:feat/auto-cloudflare-tunnel
Open

Automatic Cloudflare quick tunnel for devspace serve + styled startup UI#16
prestonlogan wants to merge 1 commit into
Waishnav:mainfrom
prestonlogan:feat/auto-cloudflare-tunnel

Conversation

@prestonlogan

Copy link
Copy Markdown

What this adds

Today devspace init requires the user to stand up their own tunnel/reverse proxy and paste the public URL by hand. This PR adds an opt-in "Automatic Cloudflare quick tunnel" mode so devspace serve can expose itself publicly on its own — no second terminal, no manual URL — plus a clack-styled startup summary that matches the existing setup screens.

It's fully opt-in and the manual-URL flow is unchanged.

Behavior

devspace init now asks how the host should be reached:

  • Automatic Cloudflare quick tunnel (recommended) → persists "tunnel": "cloudflare" in config.json
  • Manual public URL → existing behavior, unchanged

devspace serve when the tunnel is enabled:

  1. Resolves cloudflared from PATH, then ~/.devspace/bin, auto-installing the official release if missing.
  2. Runs cloudflared tunnel --url http://<host>:<port> --no-autoupdate and captures the https://<random>.trycloudflare.com URL.
  3. Sets DEVSPACE_PUBLIC_BASE_URL so the tunnel hostname is added to the Host-header allowlist via the existing loadConfig() path.
  4. Prints a styled summary box and tears the tunnel down on SIGINT/SIGTERM/exit.

Per-run overrides: devspace serve --tunnel / --no-tunnel, or DEVSPACE_TUNNEL=cloudflare|none. CLOUDFLARED_BIN points at a specific binary.

Example

┌  DevSpace
◇  Cloudflare tunnel ready  https://poultry-chevy-console-criteria.trycloudflare.com
◇  Server running (Cloudflare tunnel live) ──────────────────────────────╮
│  Local   http://127.0.0.1:7676/mcp                                      │
│  Public  https://poultry-chevy-console-criteria.trycloudflare.com/mcp   │
│  Roots   /Users/me/Development                                          │
│  Auth    Owner password approval required                               │
╰─────────────────────────────────────────────────────────────────────────╯
└  Press Ctrl+C to stop. Keep this terminal open — open a new tab for other work.

Files

  • src/cloudflare-tunnel.ts (new) — cloudflared resolve/install + quick-tunnel lifecycle. All spawns use shell: false.
  • src/cli.ts — init tunnel-mode prompt, tunnel-aware serve(), styled output, --tunnel/--no-tunnel, help text.
  • src/user-config.tsDevspaceUserConfig.tunnel?: "cloudflare".

Security considerations

  • All spawn/spawnSync calls use shell: false with array args; the only interpolated value (localBaseUrl) is built from validated config and passed as a single argv element — no shell/arg injection.
  • The release asset is chosen from a fixed platform/arch allowlist (never user input); install dir is 0o700.
  • The captured public URL is matched by a tight regex (https://[a-z0-9-]+\.trycloudflare\.com), so only a real trycloudflare hostname can be set, and only that exact host is added to the allowlist (no wildcard). OAuth owner-password approval is unchanged.
  • Known tradeoff: the downloaded cloudflared is fetched over HTTPS from the official cloudflare/cloudflared releases and smoke-tested with --version, but is not checksum-pinned (trust-on-first-use — the same trust model as running cloudflared from PATH). Glad to add SHA-256 verification if you'd prefer.

Testing

  • npm run typecheck, npm run build, npm test all pass.
  • Exercised end-to-end on macOS arm64: install/resolve, quick-tunnel URL capture, Host-allowlist wiring, and teardown on Ctrl+C.

Happy to adjust naming, defaults (e.g. keep it strictly flag-gated rather than persisted), or split the styled-UI change into its own PR if you'd rather keep this focused on the tunnel.

DevSpace currently requires the user to stand up their own public tunnel or
reverse proxy and paste the resulting URL during `devspace init`. This adds an
opt-in "Automatic Cloudflare quick tunnel" mode so `devspace serve` can expose
itself publicly on its own, plus a clack-styled startup summary that matches the
existing setup screens.

What's new:
- src/cloudflare-tunnel.ts: locate `cloudflared` (PATH, then ~/.devspace/bin),
  auto-install the official release when missing, start `cloudflared tunnel
  --url`, and scrape the https://*.trycloudflare.com URL from its output.
  Honors CLOUDFLARED_BIN; all process spawns use shell:false.
- `devspace init` now asks how the host should be reached: automatic Cloudflare
  tunnel (persists `tunnel: "cloudflare"`) or a manual public URL (unchanged).
- `devspace serve` starts the tunnel when enabled, sets DEVSPACE_PUBLIC_BASE_URL
  so the tunnel hostname is added to the Host allowlist, prints a styled summary
  box, and tears the tunnel down on SIGINT/SIGTERM/exit.
- Per-run overrides: `--tunnel` / `--no-tunnel` flags and DEVSPACE_TUNNEL env.
- Help text and config type (`DevspaceUserConfig.tunnel`) updated.

Security note: the cloudflared binary is downloaded over HTTPS from the official
cloudflare/cloudflared releases and smoke-tested with `--version`, but is not
checksum-pinned (trust-on-first-use, same model as running it from PATH). Happy
to add SHA-256 verification if preferred.

Verified: `npm run typecheck`, `npm run build`, and `npm test` all pass; tunnel
start/URL-capture/teardown exercised end to end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant