Traforo
Expose local servers via tunnels. Supports WebSockets, SSE, password protection, Cloudflare CDN caching.
Install / Use
/learn @remorses/TraforoREADME
TRAFORO
HTTP tunnel via Cloudflare Durable Objects and WebSockets. Expose local servers to the internet with a simple CLI. Infinitely scalable with support for Cloudflare CDN caching and password protection.
INSTALLATION
npm install -g traforo
USAGE
Expose a local server:
traforo -p 3000
With a custom tunnel ID (only for services safe to expose publicly):
traforo -p 3000 -t my-app
Run a command and tunnel it:
traforo -p 3000 -- next start
traforo -p 3000 -- pnpm dev
traforo -p 5173 -- vite
The tunnel URL will be:
https://{tunnel-id}-tunnel.traforo.dev
OPTIONS
-p, --port <port> Local port to expose (required)
-t, --tunnel-id [id] Custom tunnel ID (prefer random default)
-c, --cache [key] Enable edge caching (optional partition key)
--password <password> Protect the tunnel with a password
-h, --host [host] Local host (default: localhost)
-s, --server [url] Custom tunnel server URL
--help Show help
--version Show version
EDGE CACHING
Cache responses at Cloudflare's edge so repeat requests never hit your local machine:
traforo -p 3000 --cache
What gets cached:
- GET requests where the origin sends cacheable Cache-Control headers (public, max-age, s-maxage)
- Static asset extensions use Cloudflare-like default fallback TTLs when cache headers are missing: 200/301=120m, 302/303=20m, 404/410=3m
What never gets cached:
- Non-GET requests
- 206 Partial Content responses (Cache API put() limitation)
- Responses with Set-Cookie, Cache-Control: no-store/no-cache/private
- Streaming responses (SSE, ndjson)
- WebSocket connections
Requests with Authorization, Cache-Control: no-cache/no-store/max-age=0,
or Pragma: no-cache bypass edge cache lookup.
Cache partitioning lets you bust all cached content by changing the key:
traforo -p 3000 --cache v1 # first deployment
traforo -p 3000 --cache v2 # new deploy, fresh cache
Each key creates a separate cache namespace. Old entries expire via TTL.
The X-Traforo-Cache response header shows HIT, MISS, or BYPASS for debugging. When BYPASS/MISS comes from the local origin path, X-Traforo-Cache-Reason explains why.
PASSWORD PROTECTION
Restrict tunnel access with a password:
traforo -p 3000 --password mysecret
Visitors in a browser see a login page. After entering the correct password
a traforo-password cookie is set and they can browse normally.
Non-browser clients (curl, APIs) get a 401 Unauthorized response with instructions to pass the password as a cookie:
curl -b 'traforo-password=mysecret' https://{tunnel-id}-tunnel.traforo.dev
WebSocket upgrade requests without the correct cookie are rejected with close code 4013.
HOW IT WORKS
- Local client connects to Cloudflare Durable Object via WebSocket
- HTTP requests to tunnel URL are forwarded to the DO
- DO sends requests over WebSocket to local client
- Local client makes request to localhost and returns response
- WebSocket connections from users are also proxied through
API ENDPOINTS
/traforo-status Check if tunnel is online
/traforo-upstream WebSocket endpoint for local client
/traforo-login POST endpoint for password login
/* All other paths proxied to local server
LIBRARY USAGE
import { TunnelClient } from 'traforo/client'
import { runTunnel } from 'traforo/run-tunnel'
const client = new TunnelClient({
localPort: 3000,
tunnelId: 'my-app',
cacheKey: 'v1', // optional: enable edge caching
password: 'mysecret', // optional: password protection
})
await client.connect()
LICENSE
MIT
Related Skills
openhue
337.3kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
337.3kElevenLabs text-to-speech with mac-style say UX.
weather
337.3kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.4kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
