How to Fix Discourse Forum /message-bus or Long Polling Errors

AI-generated summary

The discussion outlines how to resolve /message-bus or long polling errors in Discourse when using a CDN. The issue causes real-time notifications and updates to fail, negatively impacting user experience and increasing server load. The recommended solution involves separating the MessageBus domain from the CDN, configuring a reverse proxy (Nginx) to disable caching and buffering, and adjusting CDN settings to avoid interference. Key steps include setting environment variables in app.yml to enable Redis and specify the MessageBus URL, then rebuilding the Discourse app. Success can be verified using browser DevTools to check for proper polling behavior and response headers, or via a command-line curl probe to verify CORS and connectivity. Common issues include timeouts, disconnections, and authentication errors.

1. Problem

When Discourse is configured with a CDN, a common error occurs:

/message-bus/204234de907442e8b77e153786a58e5b/poll
Connection failed / timed out / abnormal status code

Impact:

  • Notifications fail: The red dot (new PM/reply) no longer appears in real time; updates may arrive late or not at all.

  • Real-time updates break: New posts/likes/votes don’t auto-refresh; manual page refresh required.

  • User experience drops: “Connection lost” messages appear; interactions lag.

  • Increased server load: Frontend keeps retrying polls, adding pressure to the origin.

Reason: Discourse uses long polling to maintain real-time communication. Many CDNs enforce default caching, shortened timeouts, challenges/firewall checks, or buffering on long connections, causing interruptions or cached responses that break real-time behavior.


2. General Approach (Stability First)

  • Domain separation: Route MessageBus through a dedicated domain that connects directly to the origin.

  • Reverse proxy (Nginx) layer:

    • Enable CORS for /message-bus.

    • Disable proxy buffering, relax timeouts, explicitly forbid caching.

  • CDN layer (if still used):

    • Configure /message-bus/* with no caching, extended timeout, no JS challenges/CAPTCHA/rate limiting, and cookie/authorization passthrough.

    • Or bypass CDN entirely.


3. Implementation Steps

1) Configure Discourse Environment Variables

Edit app.yml (usually at /var/discourse/containers/app.yml) and add/modify under env::

env:
  DISCOURSE_MESSAGE_BUS_REDIS_ENABLED: true
  DISCOURSE_LONG_POLLING_BASE_URL: "https://messagebus.example.com"

Apply changes (official deployment):

cd /var/discourse
./launcher rebuild app

Explanation:

  • DISCOURSE_LONG_POLLING_BASE_URL tells the frontend to use the MessageBus domain.

  • REDIS_ENABLED should remain enabled.


2) DNS & Certificate

  • Point messagebus.example.com directly to the origin, bypassing CDN (best practice).

  • Set up a valid HTTPS certificate for the domain.


3) Nginx (MessageBus domain) Reverse Proxy & CORS

Add or update the following in the server block for messagebus.example.com:

location ^~ /message-bus {

    # (1) Handle CORS preflight (OPTIONS)
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;
        add_header 'Access-Control-Max-Age' 1728000 always;
        add_header 'Content-Type' 'text/plain; charset=UTF-8' always;
        add_header 'Content-Length' 0 always;
        return 204;
    }

    # (2) Reverse proxy to Discourse
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    # or, if standalone:
    # proxy_pass http://127.0.0.1:3000;

    # (3) Prevent duplicate CORS headers
    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Credentials;
    proxy_hide_header Access-Control-Allow-Methods;
    proxy_hide_header Access-Control-Allow-Headers;
    proxy_hide_header Access-Control-Max-Age;

    # (4) Normal CORS for requests
    add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;

    # (5) Long polling stability settings
    proxy_read_timeout    120s;
    proxy_send_timeout    120s;
    proxy_connect_timeout 60s;

    proxy_buffering off;
    add_header X-Accel-Buffering no always;

    # (6) Explicitly forbid caching
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}

:warning: Security note: If Access-Control-Allow-Credentials: true is used, Origin must not be *; it must match the exact forum domain.


4) CDN Rules (if forum still behind CDN)

Recommended: set no cache + extended timeout + bypass WAF/rate-limiting for these paths:

Regex example:

^/(session|login|message-bus|admin|u|users)(/|$)

Policy:

  • No browser/node caching (no-store/no-cache).

  • Upstream/read/idle timeout ≥ 60–120s.

  • Disable JS challenge/CAPTCHA/bot management.

  • Pass through cookies & Authorization headers (do not strip).


4. How to Verify Success

1) Browser DevTools → Network

On the forum page:

  • Observe /message-bus/…/poll.

  • Request should “hang” for ~20–60s, then return 200 (possibly empty).

  • Next poll request is triggered automatically.

Check response headers:

  • Access-Control-Allow-Origin: https://bbs.example.com

  • Cache-Control: no-store

  • No Age, X-Cache: HIT, or CF-Cache-Status: HIT (means not cached).

Common issues:

  • Fixed 10s/30s errors → edge/origin timeout.

  • 504/524: timeout.

  • 499: intermediate layer disconnect.

  • 403/401: WAF/auth blocking.


2) Command-Line Quick Probe (optional)

Check connectivity & headers (not full polling):

curl -I "https://messagebus.example.com/message-bus/health-check" \
  -H "Origin: https://bbs.example.com"

Note: Actual polls require session context; this only verifies CORS & connectivity.

2 Likes