Free secure self-hosted HTTPS tunnel in under 10 minutes.
┌───────────┐ ┌─────────────────┐ ┌────────────────┐
│ JIRA │ │ Public endpoint │ │ Local HTTP │
│ GitHub │ │ at Cloudflare: │ ┌───────────┐ │ dev server: │
│ GitLab │◄───►│ │◄───►│ WebSocket │◄───►│ │
│ Slack │ │ *.workers.dev │ └───────────┘ │ localhost:3000 │
│ etc... │ │ │ │ │
└───────────┘ └─────────────────┘ └────────────────┘
Webhooks Proxy Tunnel exposes a local HTTP endpoint to the public Internet. It works by reverse proxying HTTP requests through a Cloudflare worker over a WebSocket into your local machine's HTTP server. All through a secure HTTPS connection.
It takes just under 10 minutes to set up.
-
(5 mins) Create a Cloudflare account with the default free plan. You can always upgrade later to the Workers Paid plan if you're going to test thousands of tunnels in parallel.
-
(1 min) Install Node.js. Tested on
v22.14.0
.nvm install 22 nvm use 22
-
(15 sec) Clone the repo:
git clone https://github.com/peter-leonov/webhooks-proxy-tunnel.git
-
(45 sec) Deploy the worker:
cd webhooks-proxy-tunnel # this step will ask you to log into your Cloudflare account ( cd worker && npm i && npm run deploy )
-
(2 min) Then open the
https://webhooks-proxy-tunnel.YOUR_ACCOUNT.workers.dev
link from the console output above and follow the instructions there.
The tool uses cryptographically random unique tunnel IDs (UUID v4) to avoid collisions, but also to provide basic security out of the box. It's not possible to connect to the worker without knowing the tunnel ID. But we all know that security through obscurity can get us only so far. You can significantly increase the security by generating a secret token that the client will use to authenticate with the worker. This way without knowing the secret token it is impossible to connect to any tunnel disregarding the tunnel ID.
npm run generate-secret
This automatically redeploys the worker with the new secret token set as an environment variable. This enables the worker to authenticate the client requests. The client will automatically pick the token from .env
and send it on websocket connection to the worker.
You can rename the worker by updating the name
field in the worker/wrangler.jsonc
file. This will change the public endpoint URL to reflect the new name. A good way is to append a random string to the name, e.g. webhooks-proxy-tunnel-123abc
.
npm run rename-worker
npm run deploy
Then remove the old worker from your Cloudflare account to avoid confusion. You can do this in the Cloudflare dashboard.
This tunneling solution is free. It's expected that you self host it on your Cloudflare Free plan. It should take under 10 minutes to deploy the whole thing from scratch and will cost you nothing, require no EULA agreement, no fine text attached, no data protection issues. Just your laptop and your trusty Cloudfare account.
Also, it is a really simple project, should take no longer than 30 mins to audit all the code. It is basically an HTTP server (the Worker) + a simple 1:1 pub/sub bus (the Durable Object) + a straightforward tunnel (over a WebSocket over HTTPS) + trivial tunnel client (Node.JS client).
The main limitation so far is that it does not stream neither the request nor the response. This means that the whole request body data has to fit in memory (and likely be under ~100MB to fit into CF workers memory limitations). Same for the response body. It does support posting binary data though (for both the requests and responses).
It does support multiple parallel tunnels with unique IDs.
Should you need to fine tune the requests that the tunnel client makes, please, inspect the client/src/index.ts
source code on your own as the client is not a fully featured CLI yet. It's about 50 lines of simple Node.js HTTP code. Also, pull requests are welcome!
See the CHANGELOG for the latest changes.
The monorepo is:
- the CF worker that does most of the work
- the client that forwards the requests from the tunnel locally
- extra: a demo HTTP server that echoes requests back (so you don't spend AI tokens creating one)
- If this project grows any big try using the lazy websocket API that allows the DOs to hibernate to even further reduce potential costs.
Feel free to create a PR with any extension you find worthy a PR.