OdooNginxWebSocketDebugging

Why Your Odoo bus.Bus Errors Are Actually an Nginx Problem

2026-02-156 min read

If you have ever seen bus.Bus: longpolling delayed on cursor close in your Odoo logs, or noticed that real-time notifications stop working after a few minutes of use, you are almost certainly looking at an Nginx misconfiguration — not an Odoo bug. This is one of the most frequently misdiagnosed issues in Odoo DevOps, and the fix is straightforward once you understand what is actually happening.

What bus.Bus Does

Odoo's real-time features — chat messages, activity notifications, POS updates, IoT events — rely on a long-polling mechanism called bus.Bus. Long-polling means the client opens an HTTP connection to the server and leaves it open, waiting for the server to push a notification. When something happens, the server responds and the client immediately opens a new long-lived connection.

In Odoo 16 and 17, this was upgraded to WebSockets for better performance. In earlier versions it was pure long-polling. Either way, both mechanisms require the same thing from Nginx: the ability to hold an open connection without timing it out or buffering the response body.

By default, Nginx does neither of those things. A standard Nginx proxy configuration will time out long-lived connections and buffer response bodies — both of which silently break bus.Bus in ways that look like application errors.

The Three Nginx Settings That Break bus.Bus

1. proxy_read_timeout

The default value is 60 seconds. Long-polling connections are designed to stay open for up to 50 seconds waiting for a notification. If Nginx cuts the connection at 60 seconds, it usually works — but under any load the timing becomes unreliable. The symptom is notifications that sometimes work and sometimes don't, with no obvious pattern. Set this to at least 120 seconds for bus.Bus routes.

2. proxy_buffering

When proxy_buffering is on (the default), Nginx collects the entire response body from the upstream before sending it to the client. For a long-polling response that the server holds open, this means the client never receives anything until the connection closes — which is the exact opposite of the intended behaviour. You must set proxy_buffering off for the longpolling location block.

3. WebSocket upgrade headers (Odoo 16+)

WebSocket connections require an HTTP Upgrade header exchange. If Nginx does not pass the Upgrade and Connection headers through to the upstream, the WebSocket handshake fails silently and Odoo falls back to polling — or fails entirely with WebSocket connection failed errors in the browser console.

The Correct Nginx Configuration

Here is the complete Nginx server block for a production Odoo deployment. The critical sections are the longpolling and websocket location blocks:

upstream odoo {
    server 127.0.0.1:8069;
}
upstream odoochat {
    server 127.0.0.1:8072;
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # Odoo web client
    location / {
        proxy_pass http://odoo;
        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;
        proxy_read_timeout 720s;
        proxy_connect_timeout 720s;
        proxy_send_timeout 720s;
        proxy_buffering off;
    }

    # Odoo longpolling / bus.Bus (Odoo 15 and earlier)
    location /longpolling {
        proxy_pass http://odoochat;
        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;
        proxy_read_timeout 720s;
        proxy_buffering off;
    }

    # WebSocket support (Odoo 16+)
    location /websocket {
        proxy_pass http://odoochat;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_read_timeout 720s;
        proxy_buffering off;
    }

    # Static files
    location ~* /web/static/ {
        proxy_pass http://odoo;
        proxy_cache_valid 200 60m;
        proxy_buffering on;
        expires 864000;
        add_header Cache-Control "public, immutable";
    }
}

Diagnosing Whether Nginx Is the Problem

Before editing Nginx, confirm this is the issue. Open your browser developer tools, go to the Network tab, and filter for WebSocket or longpolling requests. If you see connections that open successfully and then fail after 60 seconds, or WebSocket connections that are rejected with a 400 error, Nginx configuration is your culprit.

You can also check the Nginx error log directly: tail -f /var/log/nginx/error.log while triggering a bus.Bus event. Upstream timeout errors confirm the diagnosis.

The Result

After applying the correct Nginx configuration, bus.Bus errors disappear and real-time features work reliably. This fix takes 10 minutes to implement and test. The time lost diagnosing it incorrectly as an Odoo application bug can be days. Now you know where to look first.

← Back to BlogDiscuss Your Infrastructure →