rocket.chat на своём сервере

Rocket.Chat на своём сервере: развёртывание и настройка

Развёртывание Rocket.Chat на своём сервере даёт компании корпоративный мессенджер, который полностью остаётся под контролем ИТ-службы: переписка, файлы и учётные записи не уходят во внешние облака и остаются в периметре компании. В этой статье мы проходим весь путь инженера: от расчёта ресурсов под 50, 200 и 500 сотрудников до развёртывания через Docker Compose с MongoDB replica set, интеграции с Active Directory и LDAP, харденинга по официальному руководству безопасности, резервного копирования и обновлений без простоя пользователей.

Rocket.Chat на своём сервере: развёртывание и настройка

Развёртывание Rocket.Chat на своём сервере даёт полный контроль над расположением данных: переписка, история сообщений и файлы остаются в инфраструктуре заказчика и не уходят во внешние облака. Платформа поддерживает сквозное шифрование переписки.

Содержание

Когда Rocket.Chat подходит корпоративу: критерии выбора и сравнение с Matrix и Mattermost

Rocket.Chat на своём сервере — это разворачивание открытой коммуникационной платформы, разработанной на TypeScript, внутри корпоративного периметра, где весь трафик, история сообщений и файлы остаются на инфраструктуре заказчика. Платформа поддерживает три модели поставки — self-hosted, облачную и air-gapped (полностью изолированную), — и именно последние две интересуют корпоративного клиента в России, который должен соблюдать ФЗ-152 и внутренние регламенты по обработке данных.

Мы рекомендуем выбирать Rocket.Chat, когда заказчику нужны три вещи одновременно: полноценный мессенджер с каналами, тредами и звонками; встроенные средства идентификации, сквозного шифрования и ролевого доступа; расширяемость за счёт публичных приложений из Rocket.Chat Marketplace и интеграции с внешними системами. Если хотя бы один из этих критериев не критичен, имеет смысл сравнить решение с Mattermost и Matrix — об этом у нас отдельный разбор с сравнением Matrix, Mattermost и Rocket.Chat.

Коротко критерии выбора, по которым мы принимаем решение на проектах:

  • организация хочет уйти со Slack или Microsoft Teams на свой сервер, но не готова к жёсткой федерации Matrix;
  • нужен веб-клиент и мобильные приложения «из коробки», без сборки форков;
  • ИБ требует SSO через Active Directory и журналирование действий администраторов;
  • предполагается интеграция с Jira, GitLab, Zabbix и собственными API через webhooks и Apps-Engine.

Mattermost — корпоративный мессенджер, исторически ориентированный на разработчиков, — выигрывает у Rocket.Chat, когда команде нужна минимальная установка на одном узле и Postgres вместо MongoDB. Matrix, децентрализованный протокол обмена сообщениями с реализациями вроде Synapse и Element, мы выбираем, когда требуется межорганизационная федерация серверов и независимость от одного вендора. Rocket.Chat побеждает там, где важны готовый каталог приложений, омниканальность (live chat для сайта, мессенджеры клиентов) и админка, понятная корпоративному ИТ-отделу без обучения.

На наших проектах в банковском и производственном секторе Rocket.Chat закрывает сразу два сценария: внутренний корпоративный чат и обращение клиентов через виджет на сайте. Это снимает с заказчика необходимость держать отдельную платформу для службы поддержки и отдельную систему для сотрудников.

Когда Rocket.Chat подходит корпоративу: ключевые критерии и ссылка на сравнение с Matrix и Mattermost

Расчёт ресурсов и подготовка сервера под 50, 200 и 500 сотрудников

Расчёт ресурсов под Rocket.Chat на своём сервере мы строим не от количества лицензий, а от профиля нагрузки: средней дневной активности (DAU), количества одновременно открытых клиентов, числа интеграций и объёма прикладываемых файлов. Сервер в первую очередь упирается в MongoDB и пиковую память Node.js-процессов, а не в CPU, поэтому при планировании сначала считаем диск и оперативную память, а уже потом ядра.

Для команды до пятидесяти сотрудников мы по нашему опыту берём один узел уровня бюджетного бизнес-сервера: несколько ядер, оперативная память среднего объёма, SSD-диск с запасом под полугодовую переписку и вложения. На такой конфигурации MongoDB живёт на той же машине, что и приложение, а резервные копии выгружаются на отдельное хранилище по сети. Этого достаточно, пока DAU не превышает примерно треть штата и интеграции ограничены типовыми (почтовые уведомления, webhook от трекера задач).

Для двухсот сотрудников мы выносим MongoDB на отдельный сервер и разворачиваем replica set из трёх узлов — это требование самой платформы для production-режима, и без него Rocket.Chat будет работать, но обновления между мажорными версиями станут болезненными. Приложение масштабируем горизонтально: два контейнера за обратным прокси Nginx, общий S3-совместимый бакет для uploads, отдельный том для логов. На этом уровне уже имеет смысл выделить ресурсы под микросервисы корпоративной редакции (presence, stream-hub, DDP-streamer), если планируется такая поставка.

Для пятисот сотрудников и более мы закладываем кластер: три узла MongoDB в replica set с отдельным арбитром по необходимости, минимум три экземпляра приложения, выделенный TURN-сервер для голосовых и видеозвонков, отдельная нода для интеграций и омниканальности. Здесь же мы заранее планируем отдельный сервер мониторинга — Prometheus с node-exporter и mongodb-exporter — и алерты на репликацию, иначе незаметное отставание secondary-узла превращается в потерю сообщений после сбоя primary.

Не делайте одну распространённую ошибку — мы сталкивались с этим у нового клиента: установка Rocket.Chat на виртуалку с тонким диском (thin provisioning) и снапшотами гипервизора без согласования с MongoDB. После трёх месяцев работы база раздулась, снапшот не удалялся, и виртуальная машина однажды утром просто остановилась по нехватке места на датасторе. С тех пор мы для MongoDB используем только толстый (eager-zeroed) диск и отдельный том под журнал.

Подготовку ОС мы выполняем по короткому списку: свежее ядро LTS-дистрибутива, синхронизация времени через chrony, отключение swap для узлов MongoDB, открытые порты только для обратного прокси и SSH с ключевой аутентификацией. Учётные записи администраторов разводим по разным группам, общий root по SSH запрещаем.

Расчёт ресурсов и подготовка сервера под 50, 200 и 500 сотрудников

Развёртывание через Docker Compose с MongoDB replica set

Развёртывание Rocket.Chat на своём сервере мы выполняем через Docker — это один из официально рекомендуемых способов установки на собственные серверы наряду с Podman и Kubernetes. Docker Compose выбираем там, где заказчику нужен один или два узла приложения и не планируется автоматическое масштабирование на десятки подов; для кластера от пятисот пользователей мы переходим на Kubernetes с Helm-чартом от вендора.

Ключевая особенность production-инсталляции — MongoDB обязана работать в режиме replica set, даже если узел один. Без replica set Rocket.Chat откажется стартовать в современных версиях, потому что использует change streams для распространения событий между подами. Мы инициализируем replica set отдельной командой после первого запуска MongoDB и убеждаемся, что в логах нет ошибок выбора primary.

Первый запуск выполняем поэтапно: сначала поднимаем только MongoDB, инициализируем replica set и лишь затем запускаем приложение. Такое разделение фаз позволяет увидеть проблемы конфигурации БД раньше, чем приложение успеет начать запись. Мы не делаем docker compose up -d всем стеком сразу при первой установке — на наших проектах в трёх случаях из десяти Rocket.Chat успевал записать первые документы до инициализации replica set, и затем приходилось чистить базу. С тех пор разделение фаз вошло в наш стандарт.

После старта проверяем три вещи: доступность по внутреннему порту, статус replica set (rs.status() должен показать PRIMARY и health: 1) и запись логов в JSON-формате для последующей передачи в систему сбора. Только после этого мы пробрасываем сервис наружу через обратный прокси.

Все перечисленные шаги опираются на единую структуру каталога на сервере, которую мы разворачиваем заранее: файл .env с общими переменными (имя хоста, корневой URL, ключ подписи сессий, параметры SMTP), compose-файл с сервисами rocketchat и mongodb, тома из ./data для устойчивости при пересоздании контейнеров и точные теги образов вместо latest, чтобы повторное docker compose up -d после перезагрузки не подтянуло мажорное обновление. Базовая структура каталога выглядит так:

				
					/opt/rocketchat/
├── docker-compose.yml
├── .env
├── data/
│   ├── mongo/
│   ├── mongo-config/
│   └── uploads/
└── backup/
				
			

HTTPS, обратный прокси Nginx и первичная настройка администратора

HTTPS для Rocket.Chat на своём сервере мы всегда терминируем на отдельном обратном прокси — это позволяет управлять сертификатами, заголовками безопасности и rate limit независимо от перезапусков приложения. В качестве прокси мы по умолчанию используем Nginx (HTTP-сервер и обратный прокси). Контейнер Rocket.Chat при этом слушает только на внутреннем интерфейсе и не публикует порт на внешний IP.

В конфигурации Nginx критичны три блока: проксирование WebSocket для каналов реального времени (заголовки Upgrade и Connection), увеличенные таймауты для долгоживущих соединений и ограничение размера тела запроса под максимальный размер загружаемого файла, согласованный с настройкой Rocket.Chat. Если значения расходятся, пользователи получают непонятные ошибки на полпути загрузки крупных вложений, и админ долго ищет проблему.

Сертификат для внешнего домена мы выпускаем через Let’s Encrypt (бесплатный удостоверяющий центр) с автопродлением через certbot; для закрытого контура используем корпоративный внутренний УЦ. В переменной ROOT_URL приложения обязательно указываем именно ту схему и хост, под которыми пользователи открывают сервис, иначе Rocket.Chat начнёт генерировать ссылки в письмах и пуш-уведомлениях с неправильным протоколом.

Первичная настройка администратора выполняется через мастер при первом обращении к веб-интерфейсу: задаём учётные данные владельца, наименование рабочего пространства, политику регистрации (для корпоратива — закрытая, только по приглашению или через SSO), параметры исходящей почты. Сразу после мастера мы заходим в раздел Workspace → Settings и фиксируем три вещи: запрещаем регистрацию по форме, отключаем стандартные публичные каналы по умолчанию, включаем требование подтверждения e-mail для всех новых учётных записей.

Мы не оставляем включёнными примеры интеграций и стандартного бота rocket.cat с дефолтным правом отправки в любые каналы. На одном из наших проектов этого хватило, чтобы внешний подрядчик через зарегистрированный webhook залил рекламные сообщения во внутренний канал. С тех пор мы отключаем встроенные интеграции до того, как заведём первого пользователя.

Конфигурацию обратного прокси, которая сводит воедино требования к 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 600s;
    }
}
				
			

Интеграция с Active Directory и LDAP: доменный вход, синхронизация групп и ролей

Интеграция Rocket.Chat на своём сервере с Active Directory (служба каталогов Microsoft на базе LDAP) — типовое требование корпоративного заказчика: пользователи должны входить под доменными учётными записями, а отключённый в кадровой системе сотрудник терять доступ к чату автоматически. Rocket.Chat поддерживает встроенное управление идентификацией и ролевой/атрибутивный контроль доступа, которые мы подключаем к корпоративному каталогу через стандартный модуль LDAP.

Подключение настраивается в админке в разделе LDAP. Минимально нужно задать адрес контроллера домена, шифрование (LDAPS на порту 636 либо StartTLS на 389), сервисную учётную запись с правом чтения каталога, базовый DN для поиска пользователей и фильтр. Для AD мы используем фильтр, исключающий отключённые учётные записи (userAccountControl), служебные и компьютерные объекты, чтобы не засорять список синхронизируемых пользователей.

Связку Rocket.Chat-атрибута с LDAP-атрибутом мы выстраиваем явно: usernamesAMAccountName, emailmail, namedisplayName, при необходимости nicknamecn. Это критично: если потом сменить маппинг, существующие пользователи могут получить дубль учётной записи. По нашему опыту, разрулить такой дубль вручную дольше, чем один раз правильно согласовать поля с владельцем каталога перед первой синхронизацией.

Для синхронизации групп мы используем механизм LDAP-групп Rocket.Chat: каждая группа из AD сопоставляется либо с ролью внутри Rocket.Chat (например, admin, bot, livechat-agent), либо с каналом, в который пользователь должен попадать автоматически. Это позволяет управлять составом чатов с той же стороны, что и доступом к другим системам — через групповые политики AD. Расписание синхронизации мы ставим раз в час; полный пересчёт ролей запускаем ночью.

Не настраивайте сразу Authentication.Background Sync = true с большим интервалом и широким фильтром на каталог в десятки тысяч записей. Мы один раз получили деградацию контроллера домена, потому что синхронизация утром совпала со входом сотрудников. С тех пор для крупных каталогов мы делаем ступенчатый запуск: сначала узкий OU, потом расширяем фильтр.

Перед включением доменного входа в админке мы всегда проверяем связку вручную — одной командой ldapsearch с сервера Rocket.Chat. Она подтверждает сразу три вещи: сеть до контроллера домена открыта, сертификат LDAPS принимается системой, фильтр находит ожидаемого пользователя. Только после успешной ручной проверки мы включаем Login with LDAP и тестируем вход одной пилотной учётной записью:

				
					ldapsearch -H ldaps://dc.example.local -D 'CN=rocketchat,OU=Service,DC=example,DC=local' \
  -W -b 'DC=example,DC=local' '(sAMAccountName=ivanov)'
				
			

Hardening и аудит безопасности: 2FA, CSP, rate limit по security-guidelines

Hardening Rocket.Chat на своём сервере мы выполняем по официальному руководству вендора (security-guidelines) и собственному чек-листу, накопленному на проектах. Платформа спроектирована безопасно по умолчанию и предоставляет управление идентификацией, сквозное шифрование и контроль доступа по ролям и атрибутам, но без явной настройки часть этих механизмов остаётся отключённой. Общие критерии выбора защищённого корпоративного мессенджера мы разбираем в отдельном обзоре безопасного мессенджера для бизнеса.

Двухфакторную аутентификацию мы делаем обязательной для всех учётных записей, не только для администраторов. В админке Workspace → Settings → Accounts → Two Factor Authentication включаем 2FA по TOTP, разрешаем резервные коды и запрещаем отказ от 2FA пользователем. Для административных операций (изменение настроек, выдача ролей, удаление каналов) включаем повторный запрос пароля и второго фактора — это страхует на случай угона активной сессии.

Заголовки безопасности задаём на стороне обратного прокси: Content-Security-Policy с разрешением только нужных доменов для медиа и шрифтов, Strict-Transport-Security с длительным max-age и includeSubDomains, X-Frame-Options для запрета встраивания, Referrer-Policy в режиме strict-origin-when-cross-origin. CSP для Rocket.Chat подбирается итеративно: первый прогон делаем в режиме Content-Security-Policy-Report-Only, собираем нарушения через report-uri, и только потом ужесточаем политику до боевого режима.

Сквозное шифрование (E2EE) включаем для каналов, в которых обсуждаются персональные данные и коммерческая тайна. На наших проектах мы не делаем E2EE глобальным по умолчанию: при включённом шифровании теряется индексация сообщений на сервере и возможность восстановить переписку администратору, что часто конфликтует с регламентом архивирования. Решение принимает заказчик, мы документируем выбор в проектной документации.

Аудит мы организуем тремя слоями: журнал действий администраторов и владельцев каналов в самом Rocket.Chat (Admin → Audit), журналы Nginx с пользовательским ID в заголовке, журналы MongoDB через auditLog. Все три потока пишем в централизованный сборщик логов и держим минимум за квартал для разбора инцидентов. На одном из проектов именно журналы Nginx позволили нам за полчаса показать заказчику, что подозрительная активность шла не от штатного пользователя, а от утёкшего токена интеграции — после чего мы отозвали токен и переподписали интеграции.

Защиту от перебора паролей мы выносим на два уровня. Внутренний rate limit Rocket.Chat ограничивает количество REST-вызовов и DDP-методов на пользователя — заводские значения мы не повышаем, а для эндпоинтов входа и сброса пароля местами снижаем. Внешний rate limit задаём на Nginx через limit_req_zone для /api/v1/login и /api/v1/users.register, чтобы перебор не доходил до приложения:

				
					limit_req_zone $binary_remote_addr zone=rc_login:10m rate=5r/m;

location ~ ^/api/v1/(login|users\.register) {
    limit_req zone=rc_login burst=10 nodelay;
    proxy_pass http://127.0.0.1:3000;
}
				
			

Бэкап MongoDB и uploads, восстановление за 15 минут

Бэкап Rocket.Chat на своём сервере состоит из двух обязательных компонентов: дамп MongoDB и копия каталога uploads с файлами вложений. Без uploads восстановленная база покажет в каналах ссылки на отсутствующие файлы — формально сервис будет работать, но история окажется неполной. Мы всегда снимаем оба компонента согласованно в одном окне резервного копирования.

Файлы загрузок мы снимаем rsync или tar, в зависимости от того, лежат ли uploads на локальном томе или в S3-совместимом хранилище. Для S3 включаем версионирование объектов на стороне хранилища — это даёт бесплатное «бэкапы за период» без дополнительных скриптов и спасает от ошибочного удаления одного файла администратором.

Расписание мы строим по правилу 3-2-1, адаптированному под нагрузку: ежедневный инкрементальный бэкап с хранением на сервере резервных копий, еженедельный полный бэкап с выносом на внешний носитель или второй ЦОД, ежемесячный архив с долгим сроком хранения. Сроки хранения мы согласуем с регламентом заказчика, а не выставляем «по умолчанию» — для одного клиента нам пришлось хранить чат-историю столько же, сколько финансовую документацию.

Восстановление за пятнадцать минут возможно только при подготовленной заранее площадке: чистый сервер с тем же docker-compose.yml, той же мажорной версией Rocket.Chat, тем же DNS-именем. В случае сбоя мы поднимаем MongoDB в replica set, накатываем последний дамп командой mongorestore --oplogReplay, возвращаем каталог uploads из копии и только потом запускаем приложение и проверяем целостность истории. Цикл занимает у нас на боевых инсталляциях около четверти часа при базе среднего размера; для крупных баз он растёт пропорционально, и тогда мы переходим на восстановление из снапшота диска плюс докатку oplog — это быстрее, чем mongorestore целиком.

Не делайте бэкап только средствами гипервизора без штатного дампа MongoDB. Мы у одного клиента восстанавливали базу из снимка VM, и после старта первичный узел replica set несколько часов догонял реплики, потому что снимок был сделан без подготовки кластера. С тех пор у нас правило: гипервизорные снапшоты — это второй уровень страховки, основной бэкап — всегда mongodump --oplog плюс отдельная копия uploads. Тестовое восстановление мы проводим раз в квартал, иначе бэкап остаётся гипотезой, а не процедурой.

Сам дамп MongoDB мы снимаем штатной утилитой mongodump. Для replica set обязательно используем флаг --oplog, чтобы получить консистентный снимок на момент окончания дампа; иначе при восстановлении часть коллекций будет отставать от других на минуты. Базовая команда дампа, которую мы ставим в расписание, выглядит так:

				
					docker compose exec mongodb mongodump \
  --host 'rs0/mongodb:27017' \
  --oplog \
  --gzip \
  --archive=/data/backup/rocketchat-$(date +%F).gz
				
			

Итог

Часто задаваемые вопросы

Ответы на часто задаваемые вопросы по теме статьи.

Выбор варианта rocket.chat на своём сервере обусловлен требованиями к суверенитету данных. Платформа поддерживает self-hosted и air-gapped варианты развертывания, что позволяет хранить всю историю переписки внутри периметра компании, исключая риски утечек через третьи стороны.
Rocket.Chat — это open-source платформа, разработанная на языке TypeScript. Это современный стек, обеспечивающий типизацию кода, высокую скорость работы и удобство поддержки для команд разработки, интегрирующих мессенджер в свои продукты.
Платформа безопасна по умолчанию: реализованы end-to-end шифрование, управление идентификацией и ролевой доступ на основе атрибутов. Эти механизмы позволяют гибко настраивать права доступа к каналам и файлам в соответствии с политикой безопасности организации.
Да, платформа предоставляет широкие возможности для интеграции. Вы можете устанавливать публичные приложения из Rocket.Chat Marketplace, разрабатывать собственные решения через Apps-Engine и подключать внешние системы, такие как CRM, таск-трекеры и системы мониторинга.
Для стабильной работы в продакшене рекомендуется использовать контейнеризацию. Официально поддерживаются и рекомендуются методы развертывания через Docker, Podman или Kubernetes, что упрощает масштабирование, обновление и резервное копирование сервиса.

Константин Тютюнник — ведущий инженер IT For Prof. Специализируется на проектировании отказоустойчивых инфраструктур и внедрении self-hosted решений для крупного бизнеса. Имеет опыт миграции тысяч пользователей с проприетарных платформ на открытые стандарты.

Мы помогаем компаниям перейти на защищенные каналы связи. Закажите развертывание корпоративного мессенджера на вашем сервере с настройкой LDAP, бэкапов и отказоустойчивого кластера.

Поделиться: