Skip to content

Launch hosted captun.sh tunnels#16

Open
mmkal wants to merge 7 commits into
mainfrom
hosted-captun-sh
Open

Launch hosted captun.sh tunnels#16
mmkal wants to merge 7 commits into
mainfrom
hosted-captun-sh

Conversation

@mmkal
Copy link
Copy Markdown
Contributor

@mmkal mmkal commented May 23, 2026

Summary

Adds the hosted captun.sh path so users can run npx captun 3000 without first deploying their own Worker, and reshapes the pre-user API around gateway-owned tunnel URLs.

  • defaults missing local config to the hosted https://captun.sh gateway
  • changes createCaptunTunnel to connect with { gateway, name, token, fetch } and wait for the gateway to return { url, token }
  • renames the low-level Cap'n Web accept APIs to acceptFetcherCapability and acceptFetcherCapabilityFromSocket
  • updates the CLI, deploy wizard, config file, smoke scripts, benchmarks, docs, and hosted browser demo to use gateway/token
  • reserves product/control-plane tunnel names, serves www.captun.sh, and redirects the apex host to www
  • adds CONTEXT.md and ADR-0001 to keep the Fetcher Capability / Tunnel / Gateway language clear

#20 is superseded by this shape; hosted rate limiting and ownership controls should be rebuilt on top of the gateway-owned protocol.

Example

import { createCaptunTunnel } from "captun";

const tunnel = await createCaptunTunnel({
  fetch: (request) => Response.json({ path: new URL(request.url).pathname }),
});

console.log(tunnel.url); // https://abc123.captun.sh

Self-hosted use now passes the gateway URL, not a tunnel URL template:

npx captun 3000 --gateway 'https://captun.youraccount.workers.dev' --token abc123

Verification

  • pnpm run check
  • pnpm test
  • pnpm run build
  • pnpm exec vitest run test/worker.test.ts test/e2e.test.ts examples/weather-reporter/e2e.test.ts
  • CAPTUN_PUBLIC_E2E=1 pnpm exec vitest run test/public-hosted.test.ts
  • deployed captun-public to Iterate prd with captun.sh/* and *.captun.sh/*

Note

High Risk
Large breaking public API/protocol change plus a new untrusted public ingress (hosted captun.sh) before documented ownership and rate-limit controls land.

Overview
This PR launches the hosted captun.sh path and reshapes the public tunnel API around gateway-owned addressing.

Hosted product: With no local config, npx captun 3000 and createCaptunTunnel({ fetch }) default to https://captun.sh. The Worker adds apex→www redirect, a static landing page, /captun.browser.js for an in-tab demo, reserved tunnel names, and gated live e2e in test/public-hosted.test.ts.

Protocol & API: Clients connect to a gateway URL with query params (captun-connect, captun-name, optional captun-token) instead of dialing /__captun-connect or building public URLs locally. createCaptunTunnel waits for the gateway’s Cap’n Web ready({ url, token }) before resolving. Low-level accept APIs are renamed to acceptFetcherCapability / acceptFetcherCapabilityFromSocket; Durable Objects store active tunnels as Fetcher stubs.

CLI & deploy: Config and flags use gateway / token (replacing serverUrl / secret); deploy writes CAPTUN_TOKEN and infers a stable gateway.* hostname for wildcard routes. The CLI router is refactored for test hooks (createCaptunCliRouter).

Docs & tooling: Adds CONTEXT.md, ADR-0001, README/quick-start reorder, and updates benchmarks, smoke scripts, and examples. pkg-pr-new publishes with --bin.

Hosted rate limits, ownership, and eviction policy are explicitly deferred (task notes); the initial public surface is intentionally minimal.

Reviewed by Cursor Bugbot for commit ce12906. Bugbot is set up for automated code reviews on this repo. Configure here.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 24, 2026

Open in StackBlitz

npx https://pkg.pr.new/captun@16

commit: ce12906

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ce12906. Configure here.

Comment thread src/cli/bin.ts
gateway,
target,
secret: input.secret ?? config?.secret,
token: input.token || config?.token,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legacy config silently uses hosted

High Severity

After upgrading the CLI, an existing ~/.config/captun/config.json that still has serverUrl and secret is parsed as Config but those fields are ignored. resolveTunnel then falls back to the public hosted captun.sh gateway with no token, so traffic can be tunneled through Iterate’s hosted service instead of the user’s self-hosted gateway.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ce12906. Configure here.

Comment thread src/worker.ts
}

async forward(tunnelName: string, request: Request): Promise<Response> {
const tunnel = this.tunnels.get(tunnelName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worker ignores CAPTUN_SECRET env

Medium Severity

The gateway only reads CAPTUN_TOKEN for tunnel admission, while older self-hosted deployments may still have CAPTUN_SECRET set in Cloudflare. After deploying this Worker without renaming the secret binding, CAPTUN_TOKEN is unset, admission skips token checks, and the gateway can accept anonymous connects even though operators believe auth is enabled.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ce12906. Configure here.

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