Tips > Data, APIs & Webhooks

Debug Webhooks Locally with ngrok or Cloudflare Tunnel

When self-hosting n8n behind a NAT or firewall, external services cannot reach your webhook URLs.

When you self-host n8n behind a NAT or firewall, external services cannot reach its webhook URLs. Expose the local instance with a tunnelling tool -- ngrok or Cloudflare Tunnel -- so services like GitHub, Stripe, or Shopify can deliver real webhook events during development without deploying to a public server. Set WEBHOOK_URL to the tunnel address so n8n shows the correct URLs.

Why do local webhooks need a tunnel?

When self-hosting n8n behind a NAT or firewall, external services cannot reach your webhook URLs. Use a tunneling tool to expose your local n8n instance to the internet during development. This lets you receive real webhook events from services like GitHub, Stripe, or Shopify without deploying to a public server.

Real-world example: You run n8n locally on localhost:5678 and need to test a GitHub webhook that fires on pull request events.

How do you expose local n8n with ngrok?

Using ngrok:

# Install ngrok (macOS)

brew install ngrok

# Start a tunnel to your local n8n

ngrok http 5678

# Output:

# Forwarding https://a1b2c3d4.ngrok-free.app -> http://localhost:5678

Then set your webhook path in n8n and configure GitHub:

# n8n Webhook node path

webhook/github/pull-requests

# Full URL to give GitHub (use the ngrok URL + production webhook path)

https://a1b2c3d4.ngrok-free.app/webhook/github/pull-requests

# Important: Use /webhook/ (production), not /webhook-test/

# and make sure the workflow is activated

How do you expose local n8n with Cloudflare Tunnel?

Using Cloudflare Tunnel (more stable for longer sessions):

# Install cloudflared

brew install cloudflared

# Start a quick tunnel (no account needed)

cloudflared tunnel --url http://localhost:5678

# Output:

# Your quick Tunnel has been created!

# https://random-words-here.trycloudflare.com

How do you make n8n show the correct webhook URL?

# Environment variable alternative (set in .env or docker-compose)

# Tell n8n its public URL so it generates correct webhook URLs:

WEBHOOK_URL=https://a1b2c3d4.ngrok-free.app/

Note: Set WEBHOOK_URL for correct URL display. Without setting WEBHOOK_URL, the n8n editor will still show http://localhost:5678/webhook/... as the production URL. Setting this environment variable makes n8n display the tunnel URL directly in the editor, reducing copy-paste errors.

This lets you develop and debug with real webhook traffic without deploying anything.

Related: Set a Unique Encryption Key and Back It Up · Use the HTTP Request Node as a Universal Connector

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

190 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book an introductory call