GitHub push events, Stripe payments, CI/CD triggers — delivered straight to your self-hosted services. No port forwarding, no static IP, no DDNS.
Trigger builds, sync mirrors, deploy on push — all on your own hardware.
Process payment webhooks locally during development. No ngrok needed.
Receive triggers for your self-hosted automation workflows from any service.
Webhook providers — GitHub, Stripe, Slack, your CI system — need to send HTTP POST requests to your server. But your home lab is behind NAT, your ISP may block inbound ports, and your IP changes every few days.
The usual workarounds are painful: port forwarding, dynamic DNS, reverse proxies, or paying for a cloud VM just to relay a few HTTP requests. HLE webhook tunnels solve this with a single command.
Create a webhook tunnel that forwards incoming requests to your local service:
hle webhook --path /hook/github --forward-to http://localhost:3000/webhook
The CLI prints a public URL like:
https://wh-a3f7b2c9e1d0f485-x7k.hle.world/hook/github
Paste that URL into your webhook provider's settings. Done. Requests to that URL are forwarded to your local service in real time.
Regular tunnels use predictable subdomains like myapp-x7k.hle.world. Webhook tunnels
use wh-a3f7b2c9e1d0f485-x7k.hle.world — 16 hex characters that are cryptographically
random. An attacker would need to guess 1 out of 18 quintillion possible URLs.
The relay server only forwards requests that match your webhook path prefix. If you registered with
--path /hook/github, requests to /admin or / are blocked with a 404
— they never reach your local service.
HLE secures the transport. But you should also verify that requests actually come from the expected provider. Most webhook services sign their payloads:
| Provider | Signature Header | What to check |
|---|---|---|
| GitHub | X-Hub-Signature-256 | HMAC-SHA256 of body with your webhook secret |
| Stripe | Stripe-Signature | Timestamp + HMAC with endpoint signing secret |
| GitLab | X-Gitlab-Token | Static secret token you configure |
| Slack | X-Slack-Signature | HMAC-SHA256 with signing secret |
Mirror push events from GitHub to your Gitea instance:
hle webhook --path /hook/github \
--forward-to http://localhost:3000/api/v1/repos/mirror/hooks/trigger
In GitHub → Repository Settings → Webhooks → Add webhook, paste the HLE URL as the
Payload URL. Set Content type to application/json and add a secret for signature verification.
Test Stripe webhooks during development without the Stripe CLI:
hle webhook --path /stripe \
--forward-to http://localhost:4242/webhook
In the Stripe Dashboard → Developers → Webhooks → Add endpoint. Select the events you
need (e.g. checkout.session.completed) and paste the HLE URL.
Receive external triggers for your self-hosted n8n automations:
hle webhook --path /webhook \
--forward-to http://localhost:5678/webhook
In n8n, create a Webhook node, copy the webhook path, and use the HLE URL with that path as the trigger URL in any external service.
Webhook tunnels include rate limiting to protect your services from abuse. Limits scale with your plan:
| Plan | Webhooks/min | Webhook tunnels | Price |
|---|---|---|---|
| Free | 30 | 1 | $0 |
| Pro | 60 | 3 | $5/mo |
| Business | 120 | 10 | $12/mo |
Rate limit headers are included in every webhook response so your provider can track usage:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
When the limit is exceeded, the server returns HTTP 429 with a Retry-After: 60
header. Most webhook providers handle 429 responses gracefully by retrying after the specified delay.
413. This is rarely an issue — most webhook payloads are a few KB.
hle webhook vs hle exposeBoth commands create tunnels, but they're designed for different use cases:
| Feature | webhook | expose |
|---|---|---|
| Auth gate (SSO) | Disabled | Enabled by default |
| WebSocket | Disabled | Enabled by default |
| Subdomain | Randomized (wh-<token>) | Predictable (<label>) |
| Path restriction | Server-enforced | None |
| Best for | Machine-to-machine callbacks | Human-facing services |
Use hle webhook for automated callbacks from external services. Use hle expose
for anything humans will visit in a browser.
Webhook tunnels persist across restarts. Set up a systemd service or Docker container to keep your webhook tunnel running permanently. See the Proxmox guide for systemd examples.
Path prefix matching is strict. If you register --path /hook/github,
only requests to /hook/github and /hook/github/* are forwarded.
Requests to /hook or / get a 404.
The free tier includes 1 webhook tunnel. Enough for one provider. Need to receive webhooks from multiple services? Upgrade your plan.
Test with curl. You can verify your webhook tunnel is working by sending a test
request: curl -X POST https://wh-your-token-x7k.hle.world/hook/test -d '{"test": true}'
Create a free account, grab your API key, and run one command.