A tunnel gives a service on your machine a public HTTPS address, such as https://payment-test.hookwatcher.com. Each request to it goes live to your local app, and your app's response goes back to the caller. Use it when the caller needs your real answer: OAuth redirects, a provider's URL verification, Slack commands, a demo for a colleague.
hwcli opens the connection, outbound from your machine over wss://, so you don't open a port, change your router or run a server that accepts connections from the internet. Cloudflare provides DNS and TLS in front of HookWatcher; the tunnel itself is the connection between hwcli and HookWatcher.
Start one
hwcli login hwcli tunnel http 3000 # this device's tunnel → localhost:3000 hwcli tunnel http 3000 --name payment-test # a name you choose, if your plan includes custom names
╭───────────────────────────────────────────────────────╮ │ HookWatcher Tunnel │ ├───────────────────────────────────────────────────────┤ │ Status ● Connected for 12s │ │ Tunnel payment-test │ │ Public URL https://payment-test.hookwatcher.com │ │ Local target http://127.0.0.1:3000 │ ├───────────────────────────────────────────────────────┤ │ Recent requests │ │ Waiting for requests… │ ╰───────────────────────────────────────────────────────╯
"Connected" appears only once HookWatcher has accepted the connection and is routing the hostname to it. Press Ctrl+C to stop; the hostname stays reserved for you. To reserve a name now and serve it later: hwcli tunnel create --name payment-test, then hwcli tunnel start payment-test --port 3000. hwcli tunnel list, status, stop and delete manage them; the dashboard's Tunnels view shows the same.
What your app receives
- The method, path, query, headers and body as the caller sent them. Bodies stream in both directions, so large uploads and downloads aren't held in memory.
X-Forwarded-For(the caller's IP),X-Forwarded-Proto: httpsandX-Forwarded-Host.Hostis your local address unless you pass--preserve-host.- Headers added by the network edge (
CF-*, earlierX-Forwarded-*) are removed, so they can't be spoofed through the tunnel. - Cookies your app sets are kept on the tunnel's own hostname: a
Domainattribute is removed.
Limits and behavior
- Your plan sets the number of tunnels, how many are connected at once, requests in flight per tunnel, the largest request body, and the monthly request and traffic allowance (see pricing). Over a limit, callers get
429or413. - Your app must start answering within 60 seconds, and a request may last up to 5 minutes; otherwise the caller gets
504. - WebSocket and other protocol upgrades aren't forwarded (
501). - If the connection drops, hwcli reconnects on its own. Requests that were in flight fail for their callers and are never re-sent, so a webhook can't reach your app twice because of a reconnect.
--secretrequires an access secret from callers (theX-Tunnel-Secretheader or a Basic auth password). It is removed before the request reaches your app.
Where requests are recorded
Only on your computer. hwcli keeps a request history in a local database and shows it in a panel on 127.0.0.1 (the link it prints). HookWatcher keeps the tunnel's connection details and monthly totals, not requests, headers or bodies.
When something goes wrong
- 404 "No tunnel here": hwcli isn't running for that hostname. Start it.
- 502 "Local service unreachable": hwcli is connected, but nothing answered on the local port. hwcli warns about this when it starts.
- 401: the tunnel requires its access secret.
- "Another hwcli session took over": the tunnel was started on another machine or terminal. One hwcli serves a tunnel at a time.
More in the documentation.