SSD Nodes Learn
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-07-24

Встановлення Rocket.Chat через Docker Compose

Покрокова інструкція розгортання Rocket.Chat на VPS. Налаштування MongoDB replica set, TLS та бекапів для стабільної роботи сервісу на Docker Compose.

Що ви створюєте

Приватний командний чат у вашій повній власності: Rocket.Chat, запущений на вашому власному VPS через Docker Compose, з шифруванням TLS та збереженням усіх повідомлень у базі даних MongoDB, яку можна резервно копіювати та переносити. Rocket.Chat — це зрілий open-source аналог Slack та Teams, що забезпечує канали, прямі повідомлення, гілки обговорень, обмін файлами, а також голосовий та відеозв'язок — і все це на обладнанні, яке ви орендуєте та контролюєте. Програма складається з одного контейнера, який запускається за кілька хвилин. Більшість потенційних проблем виникає на рівні бази даних, тому основна частина цього посібника присвячена MongoDB. Зокрема, тут розглядається одна особливість, яка часто стає несподіванкою для новачків: Rocket.Chat не працює з окремим (standalone) екземпляром MongoDB. Для роботи необхідно налаштувати replica set, навіть якщо цей "set" складається лише з одного вузла.

Prerequisites, and the RAM math nobody tells you

Оцінюйте ресурси сервера реально. Мінімально необхідні параметри для невеликої команди — 2 vCPU та 4 GB RAM. Процесу Node.js у Rocket.Chat потрібно приблизно 1–1.5 GB. MongoDB за замовчуванням виділяє під кеш WiredTiger близько половини вільного обсягу RAM. На VPS з 2 GB обидва процеси запускаються успішно, але стикаються при появі реального трафіку: кеш MongoDB зростає, heap у Node зростає, у ядра закінчуються сторінки пам'яті, і out-of-memory killer завершує найбільший процес — зазвичай mongod. Контейнер видає помилку Killed, Docker перезапускає його, і ви отримуєте чат-сервер, який падає кожні кілька хвилин під навантаженням, з яким він мав би впоратися. 2 GB достатньо для тестування у двох осіб, але це не підходить для командного сервера. Починайте з 4 GB. Виділяйте 8 GB, якщо плануєте десятки одночасних користувачів, відеодзвінки або великий обсяг завантажених файлів.

Перед початком роботи також необхідно підготувати три речі. Доменне ім'я з A record, що вказує на публічну IP-адресу VPS — функціям реального часу та мобільним клієнтам Rocket.Chat потрібне стабільне ім'я хоста, а не просто IP. Порти 80 та 443 мають бути відкриті як у фаєрволі сервера, так і в мережевому фаєрволі провайдера (у більшості панелей це окремий параметр). І чиста Ubuntu 24.04 KVM VPS з правами root або sudo. Якщо ви ще вагаєтеся, чи варто запускати чат-сервер як перший сервіс, guide to what is worth self-hosting in 2026 описує всі компроміси.

Встановлення Docker engine та плагіна Compose

Використовуйте власний apt-репозиторій Docker. Не використовуйте пакет docker.io з Ubuntu або застарілий окремий бінарний файл Python docker-compose. Сучасний Compose — це плагін Docker, який викликається командою docker compose (через пробіл, а не через дефіс). Стара версія docker-compose v1 більше не підтримується і некоректно обробляє синтаксис healthcheck та залежностей, наведений нижче.

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Перевірте наявність обох компонентів:

sudo docker version
sudo docker compose version

Важливим є результат, коли docker compose version виводить щось на кшталт Docker Compose version v2.x. Якщо виникає помилка docker: 'compose' is not a docker command, плагін не встановлено. Це призведе до незрозумілих помилок у майбутньому — виправте це зараз.

Файл compose: MongoDB як replica set з одним вузлом

Це етап, де часто припускаються помилок, тому читайте уважно. Rocket.Chat використовує change streams для передачі нових повідомлень підключеним клієнтам у режимі реального часу. Change streams доступні лише у складі replica set. Якщо вказати Rocket.Chat звичайний standalone mongod, він підключиться, не зможе відкрити change stream і потрапить у нескінченний цикл перезавантаження. Рішення просте: запустіть один звичайний контейнер MongoDB, але використовуйте --replSet та ініціалізуйте set з одним учасником.

Створіть робочу директорію та compose.yml:

services:
  mongodb:
    image: mongo:8.0
    restart: always
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--oplogSize", "128"]
    volumes:
      - mongodb_data:/data/db
      - mongodb_config:/data/configdb
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 12

  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:8.5.1
    restart: always
    depends_on:
      mongodb:
        condition: service_healthy
    environment:
      MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
      MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
      ROOT_URL: "https://chat.example.com"
      PORT: "3000"
    ports:
      - "127.0.0.1:3000:3000"

volumes:
  mongodb_data:
  mongodb_config:

Деякі налаштування вибрано навмисно. Порт Rocket.Chat опубліковано на 127.0.0.1:3000, а не на 0.0.0.0 — сам додаток не має TLS, тому доступ до нього має мати лише reverse proxy на цій же машині; прив'язка до всіх інтерфейсів відкриє сторінку логіна з відкритим текстом у публічному інтернеті. MongoDB взагалі не опубліковано на хості; вона доступна лише через внутрішню мережу Compose під іменем mongodb, що є хостнеймом, який використовує MONGO_URL. MONGO_URL містить ?replicaSet=rs0 — якщо прибрати цей параметр, драйвер вважатиме сервер standalone, навіть якщо це replica set, і change streams не працюватимуть. MONGO_OPLOG_URL вказує на базу даних local, де зберігається oplog; сучасний Rocket.Chat віддає перевагу change streams, але цей параметр не зашкодить і забезпечить сумісність зі старим кодом. depends_on використовує condition: service_healthy, тому Compose чекатиме на відповідь MongoDB на ping, перш ніж запустити Rocket.Chat — для цього потрібен healthcheck.

Використовуйте фіксовані теги версій для обох образів — mongo:8.0 та конкретний реліз Rocket.Chat, наприклад 8.5.1 — і ніколи не використовуйте :latest, оскільки це перетворить автоматичне docker pull на випадкове оновлення, яке неможливо відкотити. Перед фіксацією версій перевірте поточний стабільний реліз Rocket.Chat та підтримувані ним версії MongoDB. Rocket.Chat публікує машиночитабельний документ з інформацією для кожного релізу: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' повертає compatibleMongoVersions: ["8.0"] для 8.5.1, тому mongo:8.0 — єдиний підтримуваний двигун, плюс прапор lts, який вказує, чи є цей реліз версією з довгостроковою підтримкою (LTS), яку варто фіксувати для сервера, який ви не хочете обслуговувати вручну.

Ініціалізація replica set

Запустіть стек:

sudo docker compose up -d

Rocket.Chat почне одразу аварійно завершувати роботу, а Docker буде постійно перезапускати його — це очікувана поведінка, оскільки replica set ще не створена. Створіть її вручну:

sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'

Правильний результат — { ok: 1 }. Протягом кількох секунд один вузол обере себе основним (primary); перевірте це командою:

sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'

Результат має бути PRIMARY. Найважливіший параметр на цій сторінці — аргумент host: "mongodb:27017". Якщо запустити звичайний rs.initiate() без списку учасників, MongoDB оголосить назву replica set за внутрішнім hostname контейнера — випадковий хеш на кшталт a1b2c3d4e5f6. Rocket.Chat, підключаючись зі власного контейнера, не зможе розпізнати це ім'я. Через це драйвер MongoDB не зможе виконати DNS-запит і буде нескінченно циклічно реєструвати помилку MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6. Завжди ініціалізуйте з явним ім'ям сервісу, яке відповідає вашому MONGO_URL.

Перший запуск: спостерігайте за процесом

Після того як set стане primary, наступний перезапуск Rocket.Chat пройде успішно та розпочне міграції під час першого запуску. Стежте за логами:

sudo docker compose logs -f rocketchat

Ви чекаєте на рядок зі стартовим банером:

+--------------------------------------------+
        SERVER RUNNING
   Rocket.Chat Version: 8.5.1
        NodeJS Version: 22.22.3 - x64
+--------------------------------------------+

Перший запуск триває довго — додаток виконує міграції бази даних та створює індекси, тому зачекайте 1–2 хвилини. Якщо в логах повторюється MongoServerSelectionError: Server selection timed out after 30000 ms з описом топології типу ReplicaSetNoPrimary, це означає, що replica set не ініціалізовано; якщо повторюється getaddrinfo ENOTFOUND з випадковим хешем, це означає, що ініціалізація відбулася з неправильним host. У будь-якому разі, поверніться на один крок назад. Коли з'явиться SERVER RUNNING, Rocket.Chat почне прослуховувати 127.0.0.1:3000; після цього можна налаштовувати справжнє hostname та TLS.

Використовуйте TLS

Ніколи не відкривайте Rocket.Chat через звичайний HTTP. Якщо ви увійдете через http:// один раз, ви передасте свій пароль адміністратора будь-кому на шляху передачі даних. Налаштуйте термінацію TLS на реверс-проксі на тому ж сервері та перенаправляйте трафік на 127.0.0.1:3000. Важливі два моменти: проксі має передавати заголовки WebSocket upgrade, оскільки Rocket.Chat працює в режимі реального часу і не працюватиме без них; а ROOT_URL контейнера має точно відповідати публічній HTTPS-адресі, яку вводять користувачі.

Почніть зі звичайного HTTP nginx server block, який проксіює запити до додатка та передає заголовки upgrade. Збережіть його як /etc/nginx/sites-available/rocketchat, створіть символьне посилання в sites-enabled та перезавантажте:

server {
    listen 80;
    server_name chat.example.com;

    client_max_body_size 100M;

    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-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Залиште його на порту 80 на даний момент — блок з listen 443 ssl; без сертифіката навіть не пройде sudo nginx -t. Перезавантажте nginx (sudo nginx -t && sudo systemctl reload nginx), потім отримайте сертифікат. Найпростіший шлях на Ubuntu — це Let's Encrypt TLS certificates with Certbot and nginx: certbot --nginx перепише наведений вище блок, додавши listen 443 ssl;, рядки ssl_certificate та автоматичне перенаправлення з 80 на 443, а також налаштує автоматичне оновлення. Якщо ви вже використовуєте кілька контейнерів за одним проксі, Traefik with automatic TLS for many Docker apps є зручнішим варіантом — додайте мітки router та service до сервісу rocketchat, і Traefik сам запитуватиме та оновлюватиме сертифікат без використання nginx block. У будь-якому випадку, встановіть ROOT_URL на https://chat.example.com у compose.yml і знову запустіть sudo docker compose up -d, щоб контейнер застосував зміни. Якщо ви хочете, щоб сервер був доступний лише з вашої внутрішньої мережі, а не з публічного інтернету, використовуйте self-hosted WireGuard VPN on the VPS і прив'яжіть проксі до адреси тунелю.

Майстер першого налаштування

Перейдіть до https://chat.example.com та Rocket.Chat. Пройдіть короткий майстер налаштування. Спочатку створіть адміністративний обліковий запис — вкажіть справжнє ім'я, username, email та надійний пароль. Це єдиний обліковий запис у системі, тому не втратьте його. Далі вкажіть інформацію про організацію та сервер — назву, галузь, розмір, назву сайту та мову за замовчуванням. Ці дані мають косметичний характер, заповніть їх і продовжуйте. Потім виберіть важливий параметр: зареєструвати цей workspace у Rocket.Chat Cloud або залишити його як standalone (автономний).

Реєстрація дозволяє отримувати мобільні push-повідомлення через шлюз Rocket.Chat та маркетплейс аддонів, але створює зв'язок із control-plane хмари Rocket.Chat. Режим standalone забезпечує повну приватність сервера та відсутність зовнішніх залежностей, але push-повідомлення на iOS та Android не працюватимуть. Це пов'язано з тим, що Apple та Google не дозволяють самостійно розробленим застосункам використовувати push-сертифікати — офіційні застосунки використовують хмарний шлюз. Обирайте standalone, якщо пріоритетом є приватність і ваші користувачі працюють через web-застосунок. Обирайте реєстрацію, якщо мобільні push-повідомлення є обов'язковою умовою. Ви зможете змінити цей вибір пізніше в розділі Admin.

Обмежте доступ перед запрошенням користувачів

Rocket.Chat постачається з увімкненою функцією open registration on. За замовчуванням параметр Registration Form встановлено на Public, тому будь-хто, хто знайде URL, зможе створити обліковий запис. На публічному хості це створює вільний доступ. Перейдіть у Admin → Settings → Accounts → Registration і встановіть Registration Form на Disabled, щоб створювати облікові записи вручну або за посиланням-запрошенням, або на Secret URL. Також рекомендується вимкнути Allow Anonymous Read та Allow Anonymous Write, якщо вам не потрібен публічний канал лише для читання.

Також визначте місце зберігання завантажень. За замовчуванням для File Upload використовується GridFS, який зберігає кожне зображення та вкладення безпосередньо в MongoDB. Це спрощує налаштування, але означає, що ваша база даних — і кожен mongodump — постійно зростає через скріншоти користувачів. У розділі Admin → Settings → File Upload можна змінити сховище на локальну файлову систему або S3-сумісний bucket, а також встановити обмеження на максимальний розмір файлу. Для невеликої команди GridFS підходить, але враховуйте, що розмір резервних копій з часом зростатиме.

Резервне копіювання за допомогою mongodump

Усі ваші дані зберігаються у томі mongodb_data. Не копіюйте том під час роботи бази даних — зробіть консистентний дамп за допомогою mongodump з потоком даних у файл на хості:

sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gz

Цей архів у форматі gzipped містить увесь ваш робочий простір: користувачів, канали, повідомлення, налаштування та — якщо ви залишили завантаження в GridFS — також файли. Якщо ви перенесли завантаження у файлову систему або S3, створюйте резервну копію цього сховища окремо. Для відновлення на чисту інсталяцію спочатку ініціалізуйте replica set, а потім виконайте:

sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gz

Скопіюйте архів з сервера — у хмарне сховище, на інший сервер або будь-де, де вихід з ладу VPS не призведе до втрати бекапу — і налаштуйте запуск дампа через cron щоночі. Резервна копія, яку ви ні разу не відновлювали, є лише надією, а не бекапом; протедуйте відновлення на тимчасовому VPS, щоб переконатися в його справності до того, як це знадобиться.

Upgrades: pin tags, read the notes, respect the Mongo matrix

Два правила забезпечують стабільність оновлень. По-перше, оновлюйте Rocket.Chat по одній мажорній версії за раз. Під час запуску виконуються міграції схеми, тому перехід через одну мажорну версію неможливий; спроба оновлення з 6.x одразу на 8.x призведе до помилки міграції замість пошкодження даних. Змініть тег образу на останній реліз наступної мажорної версії, прочитайте примітки до цього релізу на предмет несумісних змін, запустіть docker compose up -d і переконайтеся, що міграція в логах завершена, перш ніж продовжувати. По-друге, дотримуйтесь матриці підтримки MongoDB. Кожна версія Rocket.Chat підтримує певний перелік версій MongoDB, інформацію про які надає curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. При оновленні MongoDB — наприклад, з 7.0 до 8.0 — переходьте через одну мажорну версію за раз і встановлюйте feature-compatibility version після кожного кроку. У MongoDB 8.0 ця команда потребує явного confirm: true, інакше система видасть помилку з вимогою повторного запуску з прапором підтвердження:

sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'

Робіть mongodump перед кожним оновленням будь-якого з компонентів. Це ваш єдиний спосіб страхування.

Режими відмови та відповідні рядки

Rocket.Chat перезапускається у циклі відразу після docker compose up, а docker compose logs rocketchat заповнюється MongoServerSelectionError. MongoDB працює, але драйвер не може вибрати primary-вузол; точний рядок помилки вказує на причину. Server selection timed out after 30000 ms з типом топології ReplicaSetNoPrimary означає, що ви не запустили rs.initiate() — у набору (set) ще немає конфігурації. getaddrinfo ENOTFOUND з випадковим хешем означає, що ініціалізацію було проведено без явного вказання host: "mongodb:27017", тому MongoDB оголосила нерозпізнаване ім'я хоста контейнера. Використовуйте sudo docker compose exec mongodb mongosh --eval 'rs.status()' для діагностики: якщо виникає помилка MongoServerError: no replset config has been received, ініціалізуйте набір; якщо відображається учасник, чий name є випадковим хешем, повторно ініціалізуйте набір, використовуючи ім'я сервісу.

Веб-інтерфейс завантажується, але процес входу триває нескінченно. Відкрийте консоль браузера, щоб побачити WebSocket connection to 'wss://chat.example.com/websocket' failed. Це майже завжди спричинено невідповідністю ROOT_URL або проксі-сервером, який не пересилає upgrade-заголовки. Переконайтеся, що ROOT_URL дорівнює точній публічній адресі, включаючи https://, а блок nginx location встановлює Upgrade та Connection "upgrade" з параметром proxy_http_version 1.1. Після будь-якої зміни перезапустіть docker compose up -d.

Контейнер постійно завершує роботу, і docker compose ps показує Restarting. docker compose logs переривається на середині рядка, а sudo dmesg | tail відображає Out of memory: Killed process 12345 (mongod) від oom-killer; код завершення — 137. На сервері закінчилася оперативна пам'ять (RAM). Потрібне рішення — збільшення VPS (мінімум 4 GB). Як тимчасовий захід додайте swap та обмежте кеш MongoDB за допомогою --wiredTigerCacheSizeGB 1 у його command, але swap лише відтермінує наступний OOM під реальним навантаженням:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

docker compose up завершується помилкою Error response from daemon: driver failed programming external connectivity ... bind: address already in use. Порт 3000 вже зайнятий — зазвичай це попередній контейнер Rocket.Chat, який не зупинився коректно, або інший додаток. Знайдіть його за допомогою sudo ss -ltnp | grep :3000, зупиніть цей процес або контейнер, або змініть хост-частину мапінгу на 127.0.0.1:3001:3000 та оновіть proxy_pass вашого проксі відповідно.

FAQ

Чи дійсно Rocket.Chat потрібен MongoDB replica set?

Так, навіть для одного сервера з одним вузлом бази даних. Rocket.Chat доставляє повідомлення в реальному часі за допомогою MongoDB change streams, а функція change streams доступна лише в replica set — standalone mongod не може їх відкрити. Вам не потрібно кілька машин; запустіть один контейнер MongoDB за допомогою --replSet rs0 і ініціалізуйте набір з одного учасника за допомогою rs.initiate(). Якщо пропустити цей крок, драйвер не знайде primary, тому Rocket.Chat потрапить у цикл перезавантаження з помилкою MongoServerSelectionError: Server selection timed out і не завершить запуск.

Скільки RAM потрібно для self-hosted Rocket.Chat?

Плануйте 4 GB як практичний мінімум і 8 GB для великої команди. Процес Node.js у Rocket.Chat використовує близько 1–1.5 GB, а MongoDB забирає приблизно половину решти RAM для кешу WiredTiger. На системі з 2 GB ці потреби конфліктують, і out-of-memory killer завершує роботу mongod при будь-якому реальному навантаженні, що призводить до помилки Killed у логах та коду виходу 137. 2 GB достатньо лише для тестування програмного забезпечення з кількома тестовими користувачами.

Як налаштувати HTTPS для Rocket.Chat?

Запустіть reverse proxy на тому ж VPS, який буде термінувати TLS і перенаправляти трафік на 127.0.0.1:3000, а також встановіть ROOT_URL контейнера на вашу публічну https:// адресу. Проксі має передавати WebSocket upgrade headers, інакше авторизація зависне. Certbot з nginx — найпростіший варіант для однієї програми; Traefik краще підходить, якщо ви запускаєте кілька контейнерів за одним проксі та хочете автоматичного керування сертифікатами.

Як зробити резервну копію self-hosted Rocket.Chat?

Використовуйте mongodump для створення цілісного дампу бази даних замість копіювання volume: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. Цей архів містить користувачів, канали, повідомлення та налаштування, а також завантажені файли, якщо ви використовуєте GridFS для зберігання. Скопіюйте архів на інший сервер, налаштуйте щоденне автоматичне резервування через cron і протестуйте mongorestore на тестовій машині, щоб переконатися у справності відновлення.

Як оновити Rocket.Chat без пошкодження MongoDB?

Оновлюйте Rocket.Chat по одній мажорній версії за раз — програма виконує міграції під час запуску і не дозволяє пропускати мажорні версії. Перед зміною тегу образу прочитайте примітки до кожного релізу. Перевірте, які версії MongoDB підтримує цільовий реліз за допомогою curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. При оновленні MongoDB переходьте через одну мажорну версію за раз і встановлюйте setFeatureCompatibilityVersion за допомогою confirm: true після кожного кроку. Завжди спочатку робіть mongodump.