Skip to content

feat: add tunnel support (ngrok, Cloudflare Tunnel)#104

Open
sergical wants to merge 1 commit intovercel-labs:mainfrom
sergical:feat/tunnel-support
Open

feat: add tunnel support (ngrok, Cloudflare Tunnel)#104
sergical wants to merge 1 commit intovercel-labs:mainfrom
sergical:feat/tunnel-support

Conversation

@sergical
Copy link
Copy Markdown

@sergical sergical commented Mar 11, 2026

Summary

Adds support for external tunnel providers (ngrok, Cloudflare Tunnel) to expose local dev servers to the internet. Closes #43.

Session trace: https://www.traces.com/s/jn7c9rx9wqywxp9a77b265qtg582p96p

What changed

Three levels of integration, each independently useful:

1. Single-app passthrough (zero config)

When one app is running and a request arrives with a non-.localhost Host header (e.g. from ngrok forwarding), portless auto-routes it to the single registered app. This means the simplest tunnel workflow just works:

portless myapp next dev       # Terminal 1
ngrok http 1355               # Terminal 2 -- auto-routed

2. Hostname aliasing (portless tunnel map/unmap/list)

For multi-app setups, explicitly map an external tunnel hostname to a portless route:

portless tunnel map myapp abc123.ngrok-free.app
portless tunnel unmap abc123.ngrok-free.app
portless tunnel list

Aliases are stored in aliases.json in the state directory and watched for changes by the proxy.

3. Managed tunnels (--tunnel flag)

Portless can start the tunnel for you, auto-register the alias, and pass the tunnel URL to the child process:

portless myapp --tunnel ngrok next dev
portless run --tunnel cloudflare next dev

The child process receives PORTLESS_TUNNEL_URL alongside the existing PORTLESS_URL. Tunnel cleanup (process kill + alias removal) happens automatically on exit.

Files changed

File Changes
proxy.ts findRoute() extended with alias lookup + tunnel passthrough fallback
types.ts Added getAliases to ProxyServerOptions
routes.ts Alias storage: loadAliases, addAlias, removeAlias, removeAliasesForRoute
tunnel.ts New: TunnelProvider/TunnelInstance interfaces, ngrok + cloudflare providers
cli.ts --tunnel flag, PORTLESS_TUNNEL env var, handleTunnel command, alias watching in proxy startup
index.ts Re-exports tunnel.ts
README.md New "Tunnels" section, updated commands/options/env vars
SKILL.md Tunnel docs, updated CLI reference and env vars tables
Tests 36 new tests across proxy.test.ts, routes.test.ts, tunnel.test.ts, cli.test.ts

Testing

  • 323 tests passing (36 new)
  • Typecheck clean
  • Lint clean
  • Zero new runtime dependencies

Support external tunnel providers for exposing local dev servers to the
internet. Three levels of integration:

1. Single-app passthrough: when one app is running, non-.localhost Host
   headers (from tunnel forwarding) auto-route to the single app.

2. Hostname aliasing: `portless tunnel map/unmap/list` maps external
   tunnel hostnames to portless routes for multi-app setups.

3. Managed tunnels: `--tunnel ngrok` or `--tunnel cloudflare` starts
   the tunnel alongside the app, auto-registers the alias, and sets
   PORTLESS_TUNNEL_URL on the child process.

Closes vercel-labs#43
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 11, 2026

@sergical is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

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.

portless + ngrok doesn't work

1 participant