Automation

Why Are n8n Webhooks Returning 404 Errors With a Load Balancer?

Fix 404 errors on n8n webhooks by verifying the WEBHOOK_URL environment variable and ensuring your load balancer correctly forwards the X-Forwarded-Proto header for SSL.

7 min read
Why Are n8n Webhooks Returning 404 Errors With a Load Balancer?

At Hostna, we operate various automation stacks that rely on precise network routing to function, and we have found that 404 errors in n8n are almost always a result of identity confusion between the application and the entry point. When an external load balancer is introduced, it acts as a middleman that can strip essential headers or alter request paths, leading the n8n instance to believe a request is invalid or destined for a different environment.

The most common cause of a 404 status code in this context is the WEBHOOK_URL environment variable not matching the actual address being called by the external service. If n8n does not recognize the incoming host or protocol, it may refuse to route the request to the active workflow, even if the workflow is technically running. To resolve this, you must align the environment configuration with the load balancer’s forwarding logic.

Symptom Probable Cause Recommended Fix
External 404 on all webhooks WEBHOOK_URL environment variable is unset or incorrect Set WEBHOOK_URL to your full public domain (e.g., https://n8n.example.com/)
404 only on SSL/HTTPS connections Missing X-Forwarded-Proto header from load balancer Configure load balancer to send X-Forwarded-Proto $scheme
404 on specific path-based routes Load balancer is stripping the path prefix before forwarding Adjust N8N_PATH or fix the ingress rewrite rules
404 on Production but not Test URLs Workflow is not activated or saved Click the ‘Execute’ toggle to activate the production endpoint

The Role of the WEBHOOK_URL Environment Variable

In a standard deploying a dedicated automation instance, the application needs to know its own public-facing identity to generate the correct URLs for external services. When you use an external load balancer, the n8n process often runs on a private IP or a different port (like 5678). Without the WEBHOOK_URL variable, n8n assumes it is being accessed via localhost, causing it to reject incoming requests that arrive with a different Host header.

You must ensure that your .env file or Docker compose configuration includes the exact URL used by the outside world. This includes the protocol (https), the subdomain, and any non-standard ports. For example, if your load balancer terminates SSL and forwards traffic to your configuring your Linux environment, the WEBHOOK_URL must reflect the https address even if the internal traffic is http.

A common mistake is forgetting the trailing slash or adding an extra one. The application expects a clean base URL. If your n8n instance is behind a load balancer that handles the SSL handshake, the application itself remains unaware of the encryption unless told otherwise. This is where header forwarding becomes critical to prevent the application from issuing 404 redirects or failing to match the route.

Header Forwarding and SSL Termination

When a load balancer terminates TLS, it sends a plain HTTP request to the backend. n8n checks the protocol to ensure it matches the WEBHOOK_URL. If the load balancer does not pass the X-Forwarded-Proto header, n8n might see an HTTP request while expecting HTTPS, leading to a routing failure. On our platform, we recommend verifying that X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host are all present in the proxy configuration.

The X-Forwarded-For header is essential for logging and rate limiting, but X-Forwarded-Proto is what usually fixes the 404 issue. Modern load balancers using a TLS 1.3 one-RTT handshake can significantly improve the time to first byte (TTFB) for your webhooks, but this performance gain is useless if the headers are stripped. The application relies on these headers to reconstruct the original request context.

If you are using Nginx as a load balancer, your configuration block should look like this:

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;
}

Path-Based Routing and Path Stripping

Another frequent cause of 404 errors is path-based routing. If your load balancer is configured to route traffic based on a prefix, such as example.com/n8n/, it may be configured to strip the /n8n/ part before sending the request to the backend. If n8n is not expecting this, or if it is configured with its own N8N_PATH variable, the resulting URL path will not match any registered webhook.

You can use tcpdump on your virtual private servers to see exactly what the load balancer is sending to the n8n port. This allows you to verify if the /webhook/ segment of the URL is still intact when it reaches the application. If the load balancer transforms /webhook/123 into /123, n8n will return a 404 because it only listens for requests starting with the webhook prefix.

tcpdump -i any -vvv -A 'port 5678'

Run this command and trigger a webhook. Look for the POST or GET line in the output. If the path looks different from what you see in the n8n editor, you must adjust your load balancer’s rewrite rules or the N8N_PATH environment variable to ensure alignment. This is a common requirement when using ingress controllers in containerized environments.

Differentiating Application 404s from Load Balancer 404s

Before diving deep into configuration, you must determine which component is actually generating the 404. A 404 from the load balancer means the request never reached n8n. A 404 from n8n means the request reached the application, but the application didn’t know what to do with it. You can distinguish these by checking the Server header in the HTTP response or by looking at the application logs.

Check the n8n logs using the following command:

docker logs n8n_container_name --tail 100

If you see an entry for the incoming request in the n8n logs followed by a 404, the issue is within the n8n configuration (usually WEBHOOK_URL or an inactive workflow). If the logs show nothing at the time of the request, the load balancer is failing to route the traffic to the correct backend IP or port. This often happens if the security groups or firewall rules on infrastructure in our facility are not permitting traffic from the load balancer’s internal IP.

Database Performance and Resource Limits

While 404 errors are usually routing issues, extreme resource exhaustion can sometimes manifest as a failure to respond, which some load balancers interpret as a 404 if they fail-over to a non-existent backup. For n8n instances with high execution volume, the database backend must be tuned. For example, a PostgreSQL database used by n8n often benefits from setting shared_buffers to 25 parts per hundred of the system RAM, while the innodb_buffer_pool_size for MySQL should be set to roughly three quarters of the available memory on a dedicated database machine.

If your machine has a 2 GB memory limit defined in a cgroup, the Node.js process might be killed by the OOM killer if it attempts to allocate more than the heap limit. When the process is restarting, the load balancer may return a 404 or 502. Monitoring your DNS record verification and server health is vital. If the Node.js event loop is blocked by a heavy transformation, the webhook might timeout. While this usually results in a 504, certain proxy configurations will return the last known cached 404 if the backend is marked as down.

Ensuring that your server has sufficient NVMe IOPS is also important for database-heavy workflows. High disk latency can delay the registration of webhooks upon startup, leading to temporary 404 errors during the first few minutes after a service restart. Always check the n8n configuration documentation for the latest environment variable requirements as the software evolves.

Final Verification Steps

If you have verified the headers and environment variables but still face issues, check the workflow status. n8n uses different URLs for ‘Test’ and ‘Production’. The Test URL only works when you have the workflow open in the editor and have clicked ‘Execute Workflow’. The Production URL only works when the workflow is toggled to ‘Active’. Trying to hit a Production URL on an inactive workflow will result in a 404 “Webhook not registered” error.

Verify your setup by following these steps:

  • Confirm WEBHOOK_URL starts with https:// if using SSL.
  • Ensure the workflow is active and saved.
  • Check that the load balancer is not changing the case of headers.
  • Verify that the service level agreement requirements for network availability are met by testing connectivity from a different network.
  • Check your security obligations regarding firewall white-listing for external webhook providers.

If the problem persists, gather the output of the tcpdump command and your docker-compose.yml file (with passwords redacted) to provide a clear picture of the data flow. This technical detail is essential for diagnosing complex routing issues within the Hostna infrastructure or any external network setup.

This article was drafted with AI assistance from Hostna’s own research pipeline and published without individual review. Tell us if anything here is wrong.

Questions people also ask3
Why does my n8n webhook return 404 only for production URLs?

This usually happens because the workflow is not activated. In n8n, production webhooks are only registered and listening when the workflow toggle is set to 'Active'. If the workflow is inactive, the application does not reserve the route, resulting in a 404 error. Ensure you have saved your workflow and toggled it on in the editor.

What environment variable is most important for n8n behind a load balancer?

The WEBHOOK_URL variable is the most critical. It tells n8n exactly what its public address is. Without it, n8n cannot correctly match incoming requests from a load balancer to its internal routes. Set this to the full URL, including https:// and your domain name, to ensure the application recognizes external traffic.

How do I know if the load balancer is causing the 404?

Check your n8n application logs using docker logs. If the request does not appear in the n8n logs at all, the load balancer is failing to forward the request to your server. If the request appears in the logs with a 404, the issue is likely a configuration mismatch within n8n or missing headers like X-Forwarded-Proto.