I have an n8n installation (latest version) running in Docker, behind an Nginx reverse proxy with SSL. Due to network requirements, external access is through a non-standard port (e.g., 8443), and the proxy internally redirects to the n8n container on its default port.
I’ve noticed strange behavior that I can’t resolve:
When an automatic trigger (for example, a Telegram webhook) activates the workflow, everything works perfectly: the flow executes completely, the logs show no errors, and there are no disconnections.
However, if I manually execute the same workflow from the editor (“Execute workflow” or “Execute node” button), after a few seconds the message “Lost connection to the server” appears in the interface. The editor disconnects, and sometimes stops responding until I reload the page. This happens even with very simple workflows that take no time to process.
Configuration details:
n8n with WEBHOOK_URL and N8N_HOST variables set to the external URL (with the non-standard port).
Nginx with WebSocket support (Upgrade, Connection) and high timeouts (proxy_read_timeout 300s, etc.).
Valid SSL certificate verified from the outside.
I’ve tried changing N8N_PUSH_BACKEND between sse and websocket, with no improvement.
The n8n logs (docker logs) only show reconnection events when the error occurs, but don’t indicate a clear cause.
Question:
Has anyone experienced disconnections that only happen during manual execution, but not with automatic triggers? Could it be that the editor uses a persistent connection (SSE/WebSocket) that the proxy cuts off prematurely, whereas webhook requests are simple HTTP requests that don’t suffer from the issue? Is there any additional configuration in Nginx or n8n to prevent the UI from disconnecting when launching a manual execution?
@n8n_ca manual runs stream results back to the editor over the push connection (/rest/push) which webhooks dont use, thats why only manual execs drop. when it disconnects open browser devtools > network and look at the /rest/push entry, is it failing the websocket upgrade (status isnt 101) or connecting then dropping after a few secs? that tells us whether its the nginx upgrade or the push backend.
To fix this, you must explicitly tell Nginx not to buffer the response and to handle the connection as a stream.
Update your Nginx configuration for the n8n location block with these specific directives:
location / {
proxy_pass http://localhost:5678; # Or your docker container name/IP
# 1. Essential for WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 2. Essential for SSE (The "Fix" for your specific issue)
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
# 3. Standard Proxy Headers
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;
# 4. Timeouts (Keep these high for long-running workflows)
proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
}
Checklist for your specific setup:
proxy_buffering off;: This is the most important line. It ensures that as soon as n8n sends a “node started” event, Nginx passes it to your browser immediately.
N8N_PUSH_BACKEND: Since you are using a reverse proxy, I recommend setting this to websocket. While sse works, WebSockets are generally more robust through Nginx if the Upgrade headers are correctly configured as shown above.
Verify WEBHOOK_URL: Ensure it includes your non-standard port.
Correct:WEBHOOK_URL=https://yourdomain.com:8443/
Browser Debugging: If the error persists, open your Browser Developer Tools (F12) → Network Tab.
Look for a request named events (if using SSE) or a 101 Switching Protocols request (if using WebSockets).
If you see the request status as “Pending” for a long time and then suddenly “Failed” or “Canceled” right when the error pops up, it confirms the proxy is killing the stream.
@n8n_ca if the editor loads fine and only the /rest/push websocket cant connect on :8443, that usually means nginx is serving that vhost over http/2, a websocket upgrade cant happen over an http/2 connection so the handshake fails while every normal request works. whats your listen line look like? if its listen 8443 ssl http2; drop the http2 (or split it onto its own listener) so /rest/push negotiates over http/1.1, that fixes the push without touching the buffering.
I understand the confusion with the generic recommendation “proxy_pass http://localhost:5678; # Or your docker container name/IP”, but in this specific scenario you must keep http://localhost:5678 and not change it to the external domain. Here’s why:
Nginx and n8n live on the same machine.
The n8n container publishes port 5678 to the host through the docker-compose mapping - "5678:5678". Therefore, from the perspective of the host system (where Nginx runs), n8n is accessible at localhost:5678 or 127.0.0.1:5678.
Nginx acts as a reverse proxy, not as an external client.
When Nginx receives an external request on port 443 (or 8443), it forwards it internally to the address you specify with proxy_pass. If you put https://domain.com:8443, Nginx would try to connect to itself through the public network, creating an infinite loop or a connection error because it would be calling itself.
The phrase “or your docker container name/IP” refers to container names or internal Docker IPs, not the public domain.
For example, if Nginx were also inside a Docker container on the same network as n8n, then you could use http://n8n:5678. But since Nginx runs directly on the host, the correct access is http://localhost:5678.
he hablado con chat gpt i me ha hecho este resumen.
Hi everyone,
I’ve been battling a persistent “Lost connection to the server” problem with n8n running behind an Nginx reverse proxy, and after digging into the logs I’m stuck on an “Invalid origin!” error for the /rest/push endpoint. I’d really appreciate any fresh eyes on this.
Setup:
n8n latest Docker image, behind Nginx on the same host.
External access is via https://n8n.example.com:8443 (non-standard port), forwarded by a firewall to the internal Nginx port 443.
Nginx listens on 443 (SSL), proxies to http://localhost:5678.
SSL certificate from Let’s Encrypt, valid and working.
Telegram webhook works fine, so basic reverse-proxy functionality is okay.
The container has been fully recreated after every change, and I’ve verified the variables are present inside the container.
Current behaviour:
The n8n editor loads fine, but after a few seconds (or immediately when running a workflow manually) the UI shows “Lost connection to the server”.
In the n8n container logs I repeatedly see:
text
Origin header does NOT match the expected origin.
(Origin: "undefined" -> "N/A", Expected: "undefined" -> "undefined", Protocol: "undefined")
ResponseError: Invalid origin!
at Push.handleRequest (/usr/local/lib/node_modules/n8n/src/push/index.ts:156:10)
So the push module is still expecting an “undefined” origin, even though I’ve set N8N_PUSH_ALLOWED_ORIGINS.
I’ve tried setting N8N_PUSH_BACKEND=websocket, same error.
The webhook from Telegram continues to work perfectly, so the issue is specific to the /rest/push SSE/WebSocket connection used by the editor.
Question:
Why is n8n still expecting an undefined origin despite N8N_PUSH_ALLOWED_ORIGINS being set? Is there a different variable or format needed? Could it be that N8N_PUSH_ALLOWED_ORIGINS is ignored when using SSE? Or is there something else in the proxy configuration that might strip the origin before it reaches n8n?
Any pointers would be greatly appreciated. I’m happy to provide additional logs or test specific scenarios. Thanks in advance!
@n8n_ca that invalid origin is n8ns push origin check (push/origin-validator). in prod it compares the browser Origin against X-Forwarded-Host + X-Forwarded-Proto (falling back to Host), and it keeps non-default ports, so on :8443 it expects exactly n8n.example.com:8443 over https. if nginx sends Host as localhost:5678 or X-Forwarded-Host without the :8443, it mismatches. check the n8n warn log, it literally prints Origin → X, Expected → Y so you see the exact mismatch, then set X-Forwarded-Host $http_host and X-Forwarded-Proto https so expected matches the origin.
Hey @n8n_ca, one correction before you try kjooleng’s last config, forcing proxy_set_header Origin isn’t the right fix here and may not even take effect reliably on the WebSocket upgrade request. The real issue, as achamm pointed out, is that n8n’s origin check builds its “Expected” value from X-Forwarded-Host + X-Forwarded-Proto, not from a manually injected Origin header.
To actually fix it:
Check the exact log line, it literally prints Origin: X → Expected: Y. Paste that exact line here; that tells us precisely what n8n is comparing.
Make sure X-Forwarded-Host includes the port, $http_host should already include :8443 if the browser is sending that in its Host header. Confirm with proxy_set_header X-Forwarded-Host $http_host; (no separate X-Forwarded-Port needed, n8n derives the port from the host header, not a separate header).
Drop N8N_PROXY_HOPS=1 temporarily if you only have one proxy layer between the browser and n8n, a mismatched hop count can cause n8n to read the wrong header in the forwarded chain.
Remove proxy_set_header Origin entirely if you added it, it’s not part of n8n’s origin validation logic and could mask the real header n8n is checking.
If you paste the exact Origin: X → Expected: Y log line from your latest attempt, that will show exactly which header is mismatched.