Rocket.Chat на сервере: частые ошибки и решения
Rocket.Chat выглядит как простая замена Slack и Mattermost — скачал образ, поднял контейнер, готово. На практике первый же запуск часто упирается в MongoDB, которая отказывается работать без replica set, а после переезда за nginx чат начинает залипать и терять сообщения в реальном времени. Ниже — конкретные ошибки, с которыми сталкиваются при развёртывании Rocket.Chat на своём сервере, и рабочие решения без танцев с бубном.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →MongoDB требует replica set — сервис не стартует
Самая частая причина, по которой контейнер Rocket.Chat крутится в рестарте или падает с ошибкой вида MongoServerError: The $changeStream stage is only supported on replica sets. Начиная с версий, где используются change streams для realtime-обновлений (а это давно уже стандарт), Rocket.Chat требует MongoDB именно в режиме replica set — даже если у вас один-единственный узел базы.
Проверить это можно, зайдя в контейнер с MongoDB:
docker exec -it rocketchat-mongo mongosh --eval "rs.status()"
Если в ответ приходит NotYetInitialized или ошибка про отсутствие конфигурации — реплика-сет не инициализирован. Исправляется одной командой:
docker exec -it rocketchat-mongo mongosh --eval "rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'mongo:27017' }] })"
Важно, чтобы host совпадал с именем сервиса в вашей docker-compose-сети, а не с localhost — иначе Rocket.Chat снаружи контейнера не сможет достучаться до primary. После инициации проверьте статус ещё раз — rs.status() должен показать узел в состоянии PRIMARY. Если у вас standalone-инсталляция MongoDB без Docker, процесс тот же, но конфиг replication.replSetName нужно прописать в /etc/mongod.conf и перезапустить сервис перед rs.initiate(). Подробный разбор установки самой MongoDB — в статье про настройку MongoDB на VPS и про её типовые проблемы.
Контейнер постоянно перезапускается (restarting / exited)
Если MongoDB уже в replica set, а Rocket.Chat всё равно уходит в цикл рестартов — смотрите логи, а не гадайте:
docker logs rocketchat-app --tail 100
Частые находки:
Unsupported Node.js version— актуально для тех, кто ставит Rocket.Chat не из официального Docker-образа, а руками из tarball. Каждая версия Rocket.Chat жёстко привязана к конкретной ветке Node.js (это указано в release notes на GitHub), и более новый или старый Node просто не даст приложению стартовать. Проще всего снять эту головную боль — использовать официальный образrocket.chat/rocket.chat, где версия Node уже зашита правильно.MongoNetworkError: connect ECONNREFUSED— MongoDB ещё не готова принимать соединения, когда стартует Rocket.Chat. В docker-compose это лечится черезdepends_onсcondition: service_healthyи healthcheck на mongo, а не просто порядком секций (сам по себеdepends_onне ждёт готовности базы).- Контейнер съедает всю память и падает по OOM — на VPS с 1-2 ГБ RAM Rocket.Chat вместе с MongoDB и Node.js укладываются в лимит с трудом, особенно на старте, когда идёт первичная индексация. Для стабильной работы нужно закладывать от 2 ГБ RAM отдельно под Rocket.Chat и ещё столько же под MongoDB, если она на том же хосте.
Рабочий минимальный docker-compose.yml:
services:
mongo:
image: mongo:6.0
restart: unless-stopped
command: mongod --replSet rs0 --oplogSize 128
volumes:
- mongo-data:/data/db
healthcheck:
test: echo "try { rs.status() } catch (e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo:27017'}]}) }" | mongosh --quiet
interval: 10s
timeout: 10s
retries: 5
rocketchat:
image: rocket.chat/rocket.chat:latest
restart: unless-stopped
environment:
- MONGO_URL=mongodb://mongo:27017/rocketchat?replicaSet=rs0
- MONGO_OPLOG_URL=mongodb://mongo:27017/local?replicaSet=rs0
- ROOT_URL=https://chat.example.com
- PORT=3000
depends_on:
- mongo
ports:
- "127.0.0.1:3000:3000"
Обратите внимание на MONGO_OPLOG_URL — без него Rocket.Chat тоже стартует, но realtime-обновления (сообщения без перезагрузки страницы) будут работать через поллинг, а не через oplog tailing, что заметно грузит базу под нагрузкой.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверWebSocket рвётся за реверс-прокси — чат зависает
Классическая картина: сайт открывается, авторизация проходит, но сообщения не приходят без ручного обновления страницы, а в консоли браузера — постоянные обрывы WebSocket connection to 'wss://...' failed. Причина почти всегда одна — nginx (или другой реверс-прокси) не пробрасывает заголовки для апгрейда соединения до WebSocket.
Рабочий конфиг nginx:
server {
listen 443 ssl http2;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
client_max_body_size 200m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 90s;
proxy_send_timeout 90s;
}
}
Три строки решают проблему: proxy_http_version 1.1, Upgrade $http_upgrade и Connection "upgrade". Без них nginx честно проксирует обычные HTTP-запросы, но WebSocket-хендшейк рвётся, и клиент Rocket.Chat откатывается на длинный поллинг — работает, но с задержками и повышенной нагрузкой на сервер. Если используете Cloudflare — убедитесь, что WebSocket включён в настройках сети (обычно включён по умолчанию, но на старых аккаунтах встречается выключенным). Про сами SSL-сертификаты, если после выпуска что-то идёт не так, — отдельная статья про проблемы с обновлением сертификата.
Отдельно проверьте proxy_read_timeout — значение по умолчанию в 60 секунд иногда рвёт долгоживущие WebSocket-сессии на медленном канале, из-за чего чат периодически «моргает» переподключением.
Файлы и аватары не загружаются
Ошибка 413 Request Entity Too Large в логах nginx или зависшая загрузка файла на 0% — это почти всегда лимит client_max_body_size, который по умолчанию в nginx равен 1 МБ. Поднимите его хотя бы до 200 МБ (пример выше), а сам лимит на размер файла настройте ещё и в самом Rocket.Chat: Admin → File Upload → Maximum File Upload Size.
Второй момент — где физически хранятся файлы. По умолчанию Rocket.Chat кладёт вложения прямо в MongoDB через GridFS, что удобно для старта, но раздувает базу и делает бэкапы MongoDB тяжелее с каждым загруженным видео или архивом. Для продакшена разумнее переключить хранилище на файловую систему или S3-совместимое хранилище: Admin → File Upload → File Upload Storage Type → FileSystem (с указанием пути, примонтированного как отдельный volume) или AmazonS3 (подходит и для MinIO, если поднимаете хранилище сами). При смене типа хранилища старые файлы автоматически не переносятся — их нужно мигрировать вручную через встроенный скрипт миграции в админке.
SMTP и push-уведомления не приходят
Письма (приглашения, сброс пароля, уведомления) молчат чаще всего по одной из двух причин:
- Неверный SMTP-хост в настройках админки, а не в переменных окружения — Rocket.Chat хранит эти настройки в базе и переопределяет ими env-переменные вроде
MAIL_URL, если они когда-то были выставлены через UI. Проверяйте Admin → Email → SMTP — там реальный источник истины. - Порт 25 заблокирован провайдером хостинга — многие VPS-провайдера блокируют исходящий 25 порт по умолчанию против спама. Используйте порт 587 с STARTTLS или 465 с SSL, и стороннего SMTP-релея (например, транзакционный сервис вроде Mailgun или Postmark), а не собственный почтовик на том же сервере.
Push-уведомления на мобильные устройства (значок и звук, когда приложение свёрнуто) в self-hosted Rocket.Chat по умолчанию идут через облачный gateway самого Rocket.Chat, для чего сервер нужно зарегистрировать в Rocket.Chat Cloud (Admin → Push → включить и привязать workspace). Полностью офлайн-инсталляция без регистрации в облаке push отправлять не будет — это ограничение архитектуры, а не баг конфигурации, и обходится только собственной реализацией через Firebase/APNs напрямую, что требует правок на стороне мобильного клиента.
Тормозит под нагрузкой на многопользовательских инсталляциях
Когда в воркспейсе счёт идёт на сотни активных пользователей, а не на десяток коллег, всплывают проблемы, которые не видны на старте:
- Отсутствие индексов на больших коллекциях. MongoDB создаёт базовые индексы сама при первом запуске, но если импортировали историю из другого мессенджера или база выросла органически за годы, стоит сверить актуальные индексы с документацией Rocket.Chat под вашу версию — расхождения бывают после апгрейдов через несколько мажорных релизов сразу.
- Один процесс Node.js — это один поток на CPU-bound операции. Rocket.Chat поддерживает горизонтальное масштабирование через несколько инстансов (
Meteor.settings+INSTANCE_IP), но за балансировщиком обязательно нужны sticky sessions — WebSocket-соединение должно оставаться на том же инстансе на всё время сессии, иначе клиент будет переподключаться и терять события. - Растущий oplog. Если
MONGO_OPLOG_URLнастроен, ноoplogSizeслишком мал для интенсивной записи, старые записи вытесняются быстрее, чем Rocket.Chat успевает их прочитать, и realtime начинает пропускать события. Ориентировочно для активного чата на несколько сотен человек имеет смысл закладывать oplog не меньше нескольких сотен мегабайт — точное число зависит от интенсивности переписки, проверяйте по факту черезrs.printReplicationInfo().
Для таких нагрузок разумнее сразу разносить MongoDB и приложение Rocket.Chat по разным машинам, а не держать всё на одном VPS — это упрощает и мониторинг, и последующее масштабирование каждого компонента отдельно. Если только начинаете разворачивать продакшен-инфраструктуру под чат, общие грабли Docker Compose на проде разобраны в статье про частые ошибки Docker Compose в продакшене.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обойтись без replica set в MongoDB для тестового стенда?
Технически можно откатиться на старую версию Rocket.Chat, которая ещё не требует change streams, но это путь в тупик — обновления и патчи безопасности перестанут накатываться штатно. Для теста проще поднять replica set из одного узла, как показано выше, это занимает минуту.
Почему после обновления Rocket.Chat перестал стартовать?
Чаще всего — рассинхрон версии Node.js (если ставили не из Docker) или несовместимая версия MongoDB. Перед мажорным обновлением сверяйтесь с таблицей совместимости в release notes на GitHub — там явно указаны поддерживаемые версии MongoDB и Node для каждого релиза.
Нужен ли отдельный сервер под MongoDB, если чат небольшой?
На старте для команды до 20-30 человек хватает одного VPS с 2-4 ГБ RAM и MongoDB с Rocket.Chat в соседних контейнерах. Разносить по разным машинам стоит, когда счёт пользователей идёт на сотни или когда нагрузка на диск от базы начинает мешать самому приложению.
Как перенести Rocket.Chat на другой сервер без потери истории?
Штатный путь — mongodump с исходной базы и mongorestore на новую, плюс перенос загруженных файлов (каталог, если storage — FileSystem, либо просто указание тех же настроек S3-бакета). Перед переносом обязательно проверьте совпадение мажорных версий MongoDB на обеих машинах.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →