Присоединяйся к обсуждению

Больше материалов, обсуждений и эксклюзивного контента — на нашем форуме.

Как развернуть RocketChat для пентест-команды: пошаговая настройка

Введение: почему RocketChat, а не Tox или Matrix

Общаться с командой через Tox не совсем удобно, поскольку если выйти с клиента, новые сообщения можно пропустить. Также неудобно заходить с другого устройства — приходится тащить за собой кучу файлов профиля. Восстановить аккаунт в случае утери нельзя, а поделиться контактом не всегда очевидно, как. Tox удобен для общения один на один, но плохо подходит для командной работы.

Matrix — неплохое решение, но его тоже нужно поднимать на своём сервере. Если заниматься чем-то серьёзным, использовать публичный matrix.org не вариант.

Мне нравится использовать корпоративные мессенджеры — Mattermost или RocketChat. У новичков может возникнуть путаница с настройкой, поэтому в этом гайде я подробно распишу, как поднять RocketChat так, чтобы весь нужный функционал работал корректно.

RocketChat — отличный вариант для приватного командного чата: удобное API, возможность создавать пользователей, выдавать права, добавлять участников в каналы программно. Разворачивается всё в Docker, поэтому при необходимости можно быстро всё удалить.

Выбор сервера для RocketChat

Выбирайте любого российского хостера — не реселлера. Так называемые «абузоустойчивые» хостинги — это скам и переплата. Не добавляйте в чат сомнительных людей, иначе на сервер накинут абузу и хостер его заблокирует.

  • Минимум 4 GB RAM
  • ОС: Debian 12 (рекомендуемый вариант)

Установка RocketChat на Debian 12: подготовка системы

apt update
apt list --upgradable
apt install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Установка Docker для RocketChat

mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Проверяем установку:

docker --version
docker compose version

Docker Compose файл для развёртывания RocketChat

Создаём рабочую директорию:

mkdir -p /opt/rocketchat && cd /opt/rocketchat
nano docker-compose.yml

Содержимое docker-compose.yml:

version: "3"

services:
  rocketchat:
    image: rocket.chat:latest
    restart: unless-stopped
    volumes:
      - ./uploads:/app/uploads
    environment:
      - MONGO_URL=mongodb://mongodb:27017/rocketchat?replicaSet=rs0
      - MONGO_OPLOG_URL=mongodb://mongodb:27017/local?replicaSet=rs0
      - ROOT_URL=https://your-domain.example
      - PORT=3000
      - DEPLOY_METHOD=docker
    depends_on:
      - mongodb
    ports:
      - "3000:3000"

  mongodb:
    image: mongo:6.0
    restart: unless-stopped
    volumes:
      - ./data/db:/data/db
    command: mongod --replSet rs0 --oplogSize 128

  mongo-init-replica:
    image: mongo:6.0
    command: >
      bash -c "sleep 5 && mongosh mongodb://mongodb:27017 --eval '
      rs.initiate({
        _id: \"rs0\",
        members: [{ _id: 0, host: \"mongodb:27017\" }]
      })'"
    depends_on:
      - mongodb

Важно: замените ROOT_URL на свой домен — иначе RocketChat будет генерировать некорректные ссылки в приглашениях и уведомлениях.

Запускаем контейнеры:

docker compose up -d

Проверка WebSocket и первичная настройка администратора

Проверяем, что все контейнеры запустились:

docker compose ps

Переходим в браузере по адресу http://ip_vps:3000 и проходим настройку: придумываем логин администратора, пароль, вводим рабочую почту, на которую придёт код подтверждения.

Создаём второй тестовый аккаунт и проверяем, приходят ли сообщения в реальном времени без перезагрузки страницы — так мы убеждаемся, что WebSocket-соединение работает корректно. С аккаунта администратора проверяем доступ в панель управления и создание чатов.

Если на этом этапе возникли ошибки — смотрим логи контейнера и консоль браузера:

docker compose logs --tail=20 rocketchat

Решение проблем с репликацией MongoDB

Проверяем статус репликации:

docker run -it --rm --network container:rocketchat-mongo-1 mongo:6.0 mongosh
rs.status()

Если появляется ошибка:

MongoServerError[InvalidReplicaSetConfig]: Our replica set config is invalid or we are not a member of it

Это значит, что MongoDB зарегистрировала себя во внутреннем реестре Docker под автоматически присвоенным именем контейнера вместо имени сервиса mongo, указанного в MONGO_URL. Исправляем:

docker exec -it rocketchat-mongo-1 mongosh

cfg = rs.conf()
cfg.members[0].host = "mongo:27017"
rs.reconfig(cfg, { force: true })

rs.status()

После этого в выводе должно появиться:

"members": [
  {
    "name": "mongo:27017",
    "stateStr": "PRIMARY",
    ...
  }
]

Часть функционала RocketChat недоступна без TLS-соединения — разберём его настройку ниже.

Настройка TLS-шифрования для RocketChat

Поскольку мы не привязываем доменное имя (Let’s Encrypt не выпускает сертификаты на IP-адреса), генерируем самоподписанный сертификат:

openssl req -x509 -newkey rsa:2048 -nodes -keyout rocketchat.key -out rocketchat.crt -days 365 -subj "/CN=ip_vps" -addext "subjectAltName=IP:ip_vps"

Установка и настройка Nginx как reverse proxy

apt install nginx

Удаляем дефолтный конфиг:

rm /etc/nginx/sites-available/*
rm /etc/nginx/sites-enabled/*

Создаём конфигурацию:

nano /etc/nginx/sites-available/rocketchat
server {
    listen 443 ssl;
    server_name ip_vps;

    ssl_certificate /root/rocketchat/rocketchat.crt;
    ssl_certificate_key /root/rocketchat/rocketchat.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;  # для WebSocket
        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 https;
    }
}

server {
    listen 80;
    server_name ip_vps;
    return 301 https://$host$request_uri;
}

Создаём symlink и проверяем конфигурацию:

ln -s /etc/nginx/sites-available/rocketchat /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

В переменных окружения RocketChat меняем протокол:

- ROOT_URL=https://ip_vps
- PORT=3000

Порт 3000 у самого RocketChat остаётся прежним — nginx проксирует запросы с 443 на 3000. Браузер будет предупреждать о самоподписанном сертификате (это ожидаемо при работе по IP без домена), но соединение уже зашифровано.

Защита панели администратора: Basic Auth

apt install apache2-utils
htpasswd -c /etc/nginx/.htpasswd your_secure_login
server {
    listen 443 ssl;
    server_name ip_vps;

    ssl_certificate /root/rocketchat/rocketchat.crt;
    ssl_certificate_key /root/rocketchat/rocketchat.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        auth_basic "Restricted Access";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_pass http://localhost: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 https;
    }
}

server {
    listen 80;
    server_name ip_vps;
    return 301 https://$host$request_uri;
}
systemctl reload nginx

Закрываем прямой доступ к порту RocketChat

Раз трафик теперь идёт через nginx на 443 порт, порт 3000 нужно закрыть от внешнего доступа — иначе Basic Auth не имеет смысла, так как RocketChat остаётся доступен напрямую в обход nginx:

services:
  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:latest
    restart: unless-stopped
    volumes:
      - rocketchat_data:/app/uploads
    environment:
      - PORT=3000
      - ROOT_URL=https://ip_vps
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - MONGO_OPLOG_URL=mongodb://mongo:27017/local
    depends_on:
      - mongo
    ports:
      - "127.0.0.1:3000:3000"

  mongo:
    image: mongo:6.0
    restart: unless-stopped
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    volumes:
      - mongo_data:/data/db
      - mongo_config:/data/configdb

volumes:
  rocketchat_data:
  mongo_data:
  mongo_config:

Закрытая регистрация и права пользователей

Отключаем открытую регистрацию через /admin/settings/Accounts, чтобы новые аккаунты создавал только администратор.

Настраиваем права доступа для ролей в разделе /admin/permissions — здесь можно ограничить, кто может создавать каналы, приглашать пользователей и управлять настройками сервера.

Новых пользователей создаём вручную через /admin/users, а в /admin/settings/Accounts запрещаем пользователям самостоятельно менять никнейм и логин — это исключает путаницу и упрощает модерацию.

Итог

Если повторить все шаги по порядку, RocketChat разворачивается с рабочим TLS-шифрованием, закрытой регистрацией, защищённой панелью администратора и без открытого доступа к порту приложения напрямую. Для генерации сложных логинов и паролей можно использовать любой надёжный генератор паролей.

Отключаем уведомления rocket.cat о невалидном URL

Если после смены ROOT_URL или работы без домена системный бот rocket.cat присылает сообщения о невалидном URL, отключить их можно через панель администратора:

/admin/settings/Message

Здесь находится настройка, отвечающая за системные уведомления такого типа — достаточно выключить соответствующий тумблер.

Как убрать бота rocket.cat из статуса «онлайн» или удалить его профиль

Если недостаточно просто отключить уведомления и хочется, чтобы системный бот не отображался как активный пользователь, это делается напрямую через базу данных MongoDB:

docker run -it --rm --network container:rocketchat-mongo-1 mongo:6.0 mongosh

Переводим всех пользователей с типом bot в статус оффлайн и деактивируем их:

db.users.updateMany(
  { type: "bot" },
  {
    $set: {
      active: false,
      status: "offline",
      statusDefault: "offline",
      roles: []
    }
  }
)

Если нужно только снять роли, не деактивируя аккаунт полностью:

db.users.updateMany(
  { type: "bot" },
  { $set: { roles: [] } }
)

После изменений перезапускаем контейнер, чтобы RocketChat подхватил новое состояние:

docker restart rocketchat-rocketchat-1

Восстановление доступа админа при утере пароля

Если пароль от административной учётной записи утерян, но в браузере осталась активная сессия — самый быстрый способ восстановить доступ следующий:

  1. Создайте новую учётную запись
  2. Сразу при создании назначьте ей роли leader и admin

Важный нюанс: если попытаться добавить роль администратора уже существующему пользователю, RocketChat запросит подтверждение паролем текущей сессии — и если пароль неизвестен, операция не пройдёт. А вот при создании новой учётной записи роли можно указать сразу, без дополнительного подтверждения — это и есть обходной путь для восстановления доступа.