Fix webhook URL issues in n8n behind a reverse proxy

Learn how to fix webhook URL issues in n8n when running behind a reverse proxy. Configure headers, env vars and SSL the right way.
Abstract background featuring wavy lines in various colors, creating a dynamic and fluid visual effect.

Why reverse proxy issues matter

Most production n8n setups sit behind a reverse proxy like Nginx, Caddy, Traefik or HAProxy. The proxy handles HTTPS, redirects and sometimes load balancing. If it is not configured correctly, webhook URLs inside the n8n editor break.

You may see webhooks generated with http://localhost:5678/ instead of your domain, or you may get timeouts when external services try to call n8n. The fix is not complicated, but you need to set the right headers and environment variables.

How n8n generates webhook URLs

When you create a workflow with a webhook trigger, the editor displays the public URL. n8n builds this URL using three variables:

  • N8N_HOST – your public domain
  • N8N_PROTOCOLhttp or https
  • WEBHOOK_URL – overrides the full public URL if needed

If none of these are set, n8n defaults to whatever it sees in the request headers. That’s why behind a proxy it often shows localhost:5678.

Key environment variables to set

In your .env file add:

N8N_HOST=automation.example.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://automation.example.com/
N8N_PORT=5678
N8N_PROXY_HOPS=1
  • N8N_HOST and N8N_PROTOCOL tell n8n what to display in webhook URLs.
  • WEBHOOK_URL is the strongest override if you want to be explicit.
  • N8N_PROXY_HOPS defines how many reverse proxies are in front. Most setups use 1.

Restart your containers after changing these values.

Reverse proxy headers you must forward

The proxy should pass these headers to n8n:

  • X-Forwarded-For – the real client IP
  • X-Forwarded-Host – the original Host header
  • X-Forwarded-Proto – the original scheme (http or https)

Without them, n8n cannot reconstruct the correct public URL.

Example Nginx config

Here’s a minimal Nginx block for n8n:

server {
    listen 80;
    server_name automation.example.com;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

For HTTPS add Let’s Encrypt with certbot or use a managed TLS proxy like Traefik or Caddy.

Example Caddy config

Caddy handles HTTPS automatically:

automation.example.com {
    reverse_proxy 127.0.0.1:5678
}

Caddy sets the headers correctly by default. That’s why it is often the easiest choice for n8n.

Common problems and fixes

  • Webhook shows localhost – set N8N_HOST, N8N_PROTOCOL and WEBHOOK_URL.
  • SSL works but webhook fails – proxy not forwarding X-Forwarded-Proto.
  • Wrong port in webhook – set N8N_PORT to 5678 explicitly.
  • Multiple proxies in chain – bump N8N_PROXY_HOPS to 2 or more.

Advanced setups

  • Load balancer + reverse proxy: If you have a cloud load balancer in front of Nginx, you may need N8N_PROXY_HOPS=2 so n8n trusts both layers.
  • Path-based routing: If you serve n8n under a path (like example.com/n8n/), set WEBHOOK_TUNNEL_URL to the exact public path. Path-based routing adds complexity, so a dedicated subdomain is cleaner.
  • Custom SSL: If you terminate TLS outside the VPS (for example in Cloudflare), still forward the correct X-Forwarded-Proto header so n8n knows requests are secure.

Best practices for production

  • Use a dedicated subdomain for n8n instead of a path.
  • Always enable HTTPS with Let’s Encrypt or a trusted certificate.
  • Test webhook URLs from the outside with curl before going live.
  • Monitor certificate expiry. Let’s Encrypt certificates last 90 days.
  • Keep proxy config in version control so changes are auditable.

FAQ

Why does n8n show http instead of https in webhook URLs?

Because it only sees plain HTTP requests from the proxy. Fix it by forwarding X-Forwarded-Proto and setting N8N_PROTOCOL=https.

Do I need N8N_HOST if I set WEBHOOK_URL?

No, WEBHOOK_URL overrides everything. Still, setting both keeps the config clear.

How many proxy hops should I set?

Set N8N_PROXY_HOPS=1 if you only have one proxy. If you have a load balancer plus a proxy, set it to 2.

Can I run n8n on a path instead of a subdomain?

Yes, but it’s tricky. Webhook URLs sometimes break with path-based routing. A dedicated subdomain is more reliable.

Does Caddy need extra headers for n8n?

No. Caddy automatically forwards the right headers. That’s one reason many users prefer it for n8n.