Receive webhooks in self-hosted n8n
Receive webhooks in self-hosted n8n on localhost with a Horizon tunnel, and set WEBHOOK_URL so n8n shows the public URL.
Give webhook services a public URL for your local n8n, and make the Webhook node show that URL instead of localhost:5678.
Before you begin
- Node.js 18 or later
- A Horizon account and the CLI (see Getting started)
- A reserved subdomain for
-s. Reserve one on the Subdomains page. - A self-hosted n8n that you can restart with environment variables
Start a tunnel
n8n listens on port 5678. Use -s with a subdomain you reserved. Without it, the subdomain is random and changes every run, so every webhook you registered would point at a dead URL. Reserved subdomains are a paid feature, see Pricing.
hrzn tunnel http://localhost:5678 -s my-appHORIZON: Tunnel connected
URL https://my-app.hrzn.run (reserved)
Forwarding http://localhost:5678
Request log https://hrzn.run/dashboard/tunnels/my-appKeep this terminal open.
Set the webhook URL
n8n runs on port 5678 and doesn't know it sits behind a proxy. Set N8N_WEBHOOK_URL to the public URL, with a trailing slash. n8n then shows that URL in the editor and registers it with external services.
export N8N_WEBHOOK_URL=https://my-app.hrzn.run/From n8n 2.35.0, WEBHOOK_URL is deprecated. It still works as an alias and n8n logs a warning on startup. On an older n8n, use WEBHOOK_URL.
n8n's reverse proxy guide also sets N8N_PROXY_HOPS=1, the number of reverse proxies in front of n8n. n8n uses it to read the right entry of X-Forwarded-For. Horizon sends X-Forwarded-For with the visitor's IP address, so set it to read the visitor's IP, for example for an IP allowlist in n8n.
export N8N_PROXY_HOPS=1Restart n8n in the same shell so it reads both variables.
Copy the URL from the Webhook node
Open a workflow and add a Webhook node. The node now shows URLs that start with https://my-app.hrzn.run/. The test URL uses the path webhook-test and the production URL uses webhook. Paste the one you need into the service that sends the webhook.
Check it works
Send a request to the test URL while the Webhook node listens for a test event.
curl -X POST https://my-app.hrzn.run/webhook-test/your-path -d '{"hello":"world"}' -H "Content-Type: application/json"The node shows the received data. Your Horizon terminal prints one line:
POST 200 /webhook-test/your-pathTroubleshooting
The Webhook node still shows localhost:5678
n8n didn't read N8N_WEBHOOK_URL. Restart n8n from the shell where you ran export, or add the variable to your container or service configuration. On n8n before 2.35.0, set WEBHOOK_URL instead.
The URL changed after a restart
You started the tunnel without -s, so Horizon gave you a new random subdomain. Restart with -s my-app and the URL stays the same. -s needs a subdomain you reserved, see Pricing.
Nothing reaches n8n
- Check that the Horizon terminal is still running.
- The test URL works only while the Webhook node is listening. The production URL works only while the workflow is active.
Next steps
- Read n8n's guide to configuring webhook URLs with a reverse proxy.
Expose a local Ollama API
Expose a local Ollama API on a public URL with a Horizon tunnel, including streaming responses and browser access with OLLAMA_ORIGINS.
Reach Home Assistant from outside your network
Reach Home Assistant from outside your network with a Horizon tunnel, with WebSocket passthrough, reverse proxy settings and the external URL.