Prompt
How do I build a local webhook testing setup without exposing my machine to the internet?
Latest observation
You can do local webhook testing without exposing your machine publicly by using a private tunnel, a local reverse proxy, or a fake webhook sender. Here are the safest practical options.
Best options
1) Use a tunneling tool in a restricted/private mode
Tools like ngrok, Cloudflare Tunnel, or LocalTunnel can expose only a specific local port temporarily, but you can reduce risk by:
- binding to a single local service only
- using authentication/access control if available
- enabling request verification on your webhook endpoint
- shutting it down when done
Pros: easy, works with real third-party webhooks
Cons: still creates an internet-facing endpoint
If your goal is truly “do not expose my machine to the internet,” use option 2 or 3 instead.
2) Simulate the webhook locally
Instead of receiving a real external webhook, run a local script or test harness that POSTs the same JSON payload to your endpoint.
Example:
curl -X POST http://localhost:3000/webhook \
-H "Content-Type: application/json" \
-d '{"event":"payment.succeeded","id":"evt_123"}'
You can also:
- save real webhook samples and replay them
- use integration tests that call your local handler directly
- mock signature headers and retry behavior
Pros: fully local, safest
Cons: not a real internet delivery path
3) Use a local webhook relay inside your private network
If the webhook sender is also under your control, set up a small internal relay:
- webhook provider sends to a service inside your LAN/VPN
- relay forwards to
localhostor a private dev machine
This keeps traffic off the public internet.
Pros: private and realistic
Cons: requires network control/VPN/internal infra
4) Run everything in Docker Compose
Put your app and a webhook simulator in the same Docker network:
- your app listens on an internal container port
- a “sender” container posts test webhooks
Example docker-compose.yml:
services:
app:
build: .
ports:
- "3000:3000"
webhook-sender:
image: curlimages/curl
depends_on:
- app
entrypoint: ["sh", "-c"]
command: >
while true; do
curl -X POST http://app:3000/webhook
-H 'Content-Type: application/json'
-d '{"event":"test"}';
sleep 10;
done
If you want to avoid exposing your app to your LAN too, bind only to localhost:
ports:
- "127.0.0.1:3000:3000"
Recommended secure setup
If you want a good balance of realism and safety:
-
Run your app only on localhost
- Bind to
127.0.0.1, not0.0.0.0
- Bind to
-
Create a webhook replay script
- Capture real payloads from docs or logs
- POST them locally
-
Verify signatures
- Add code that checks HMAC or signature headers
- Store the signing secret only in local env vars
-
Add request logging
- Log headers, body, timestamp, and signature verification result
-
Use automated tests
- Unit test webhook parsing
- Integration test the endpoint with recorded fixtures
Safety tips
- Don’t open router port forwards for webhook testing
- Don’t bind dev servers to all interfaces unless necessary
- Use firewall rules to restrict inbound traffic
- If using a tunnel, disable it after testing
- Avoid using production secrets in local tests
If you need a real third-party webhook
If the provider only delivers to public URLs, you have two safe-ish choices:
- use a tunnel service with strict access controls
- use a temporary cloud dev box/VPN-hosted test endpoint instead of your laptop
If you want, I can give you:
- a Docker Compose webhook test lab,
- a Node/Python local webhook replay script, or
- a secure ngrok/Cloudflare Tunnel setup with minimal exposure.