1. Проблема
При настройке Discourse с использованием CDN часто возникает следующая ошибка:
/message-bus/204234de907442e8b77e153786a58e5b/poll
Ошибка подключения / тайм-аут / аномальный код состояния
Последствия:
-
Сбои уведомлений: Красная точка (новое личное сообщение/ответ) больше не появляется в реальном времени; обновления могут приходить с задержкой или не приходить вовсе.
-
Нарушение обновлений в реальном времени: Новые сообщения, лайки и голоса не обновляются автоматически; требуется ручное обновление страницы.
-
Ухудшение пользовательского опыта: Появляются сообщения «Подключение потеряно»; взаимодействия работают с задержкой.
-
Увеличение нагрузки на сервер: Фронтенд продолжает повторные попытки опроса, создавая дополнительную нагрузку на исходный сервер.
Причина: Discourse использует механизм длинного опроса (long polling) для поддержания связи в реальном времени. Многие CDN по умолчанию включают кэширование, сокращают время ожидания, требуют проверки через капчу/брандмауэр или буферизуют длительные соединения, что приводит к прерываниям или возврату закэшированных ответов, нарушающих работу в реальном времени.
2. Общий подход (Приоритет стабильности)
-
Разделение доменов: Маршрутизация MessageBus через выделенный домен, который подключается напрямую к исходному серверу.
-
Домен форума (через CDN): https://bbs.example.com
-
Домен MessageBus (без CDN): https://messagebus.example.com
-
-
Слой обратного прокси (Nginx):
-
Включить CORS для /message-bus.
-
Отключить буферизацию прокси, увеличить таймауты, явно запретить кэширование.
-
-
Слой CDN (если всё ещё используется):
-
Настроить /message-bus/* с параметрами: без кэширования, увеличенный таймаут, отсутствие проверок JS/CAPTCHA/ограничения скорости, а также передача куки и заголовков авторизации.
-
Или полностью обойти CDN.
-
3. Шаги реализации
1) Настройка переменных окружения Discourse
Отредактируйте файл app.yml (обычно находится в /var/discourse/containers/app.yml) и добавьте/измените секцию env::
env:
DISCOURSE_MESSAGE_BUS_REDIS_ENABLED: true
DISCOURSE_LONG_POLLING_BASE_URL: "https://messagebus.example.com"
Примените изменения (официальное развёртывание):
cd /var/discourse
./launcher rebuild app
Пояснение:
-
DISCOURSE_LONG_POLLING_BASE_URL указывает фронтенду использовать домен MessageBus.
-
REDIS_ENABLED должен оставаться включённым.
2) DNS и сертификат
-
Настройте messagebus.example.com так, чтобы он указывал напрямую на исходный сервер, минуя CDN (лучшая практика).
-
Установите действительный HTTPS-сертификат для домена.
3) Обратный прокси (домен MessageBus) и CORS в Nginx
Добавьте или обновите следующие настройки в блоке server для messagebus.example.com:
location ^~ /message-bus {
# (1) Обработка предварительного запроса CORS (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) Обратный прокси к Discourse
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
# или, если используется standalone:
# proxy_pass http://127.0.0.1:3000;
# (3) Предотвращение дублирования заголовков CORS
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) Обычные заголовки CORS для запросов
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) Настройки стабильности для длинного опроса
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_connect_timeout 60s;
proxy_buffering off;
add_header X-Accel-Buffering no always;
# (6) Явный запрет кэширования
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}
Примечание по безопасности: Если используется Access-Control-Allow-Credentials: true, заголовок Origin не может быть *; он должен точно совпадать с доменом форума.
4) Правила CDN (если форум всё ещё находится за CDN)
Рекомендуется установить без кэширования + увеличенный таймаут + обход WAF/ограничения скорости для следующих путей:
Пример регулярного выражения:
^/(session|login|message-bus|admin|u|users)(/|$)
Политика:
-
Отключение кэширования в браузере/узлах (no-store/no-cache).
-
Таймауты upstream/read/idle ≥ 60–120 с.
-
Отключение проверки JS/CAPTCHA/управления ботами.
-
Передача куки и заголовков авторизации (не удалять).
4. Как проверить успешность
1) Инструменты разработчика браузера → Сеть
На странице форума:
-
Отслеживайте запросы /message-bus/…/poll.
-
Запрос должен «висеть» около 20–60 секунд, затем возвращать 200 (возможно, пустой ответ).
-
Следующий запрос опроса запускается автоматически.
Проверьте заголовки ответа:
-
Access-Control-Allow-Origin: https://bbs.example.com
-
Cache-Control: no-store
-
Отсутствие заголовков Age, X-Cache: HIT или CF-Cache-Status: HIT (означает, что кэширование не применено).
Распространённые проблемы:
-
Ошибки с фиксированным интервалом 10с/30с → тайм-аут на границе или исходном сервере.
-
504/524: тайм-аут.
-
499: разрыв соединения на промежуточном уровне.
-
403/401: блокировка WAF или авторизацией.
2) Быстрая проверка через командную строку (опционально)
Проверьте подключение и заголовки (не полный опрос):
curl -I "https://messagebus.example.com/message-bus/health-check" \
-H "Origin: https://bbs.example.com"
Примечание: Фактические опросы требуют контекста сессии; данная команда проверяет только CORS и подключение.