Expose a local server with an HTTPS tunnel

Guides / Workflow

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.

A HookWatcher tunnelA caller requests the public tunnel URL. HookWatcher's tunnel service sends it over the connection hwcli opened from your machine. hwcli calls your local app and the response goes back the same way.Callerprovider, browserHookWatchertunnel service: routing,limits, access secrethwcliyour machineYour applocalhost:3000connection opened by hwcli (outbound wss://)requests and responses travel inside it
A HookWatcher tunnel

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: https and X-Forwarded-Host. Host is your local address unless you pass --preserve-host.
  • Headers added by the network edge (CF-*, earlier X-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 Domain attribute 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 429 or 413.
  • 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.
  • --secret requires an access secret from callers (the X-Tunnel-Secret header 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.

Create an endpoint and capture your first webhook. No signup needed.

Start Free