NodeBB в Docker Compose: готовый файл
Классический форум на PHP обновляется по клику «обновить страницу» — для сообщества, которое хочет живого общения, это ощущается медленно. NodeBB решает это через постоянное WebSocket-соединение: новые сообщения, счётчик онлайна и уведомления прилетают без перезагрузки, а интерфейс изначально адаптирован под телефон. Ниже — рабочий docker-compose.yml, который поднимает такой форум за один docker compose up -d, с Redis под капотом, HTTPS через обратный прокси и понятным путём обновления.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Архитектура: контейнеры, база данных и место Socket.IO
Стек из двух контейнеров:
- nodebb — сам форум: Node.js-процесс, который отдаёт HTML, держит Socket.IO-соединения и рендерит темы/разделы;
- redis — база данных NodeBB (ядро поддерживает Redis, MongoDB и PostgreSQL как равноправные бэкенды) и заодно pub/sub-шина для Socket.IO, если позже понадобится несколько инстансов NodeBB за балансировщиком.
Redis для старта на одном сервере — самый простой вариант: один процесс, минимум настройки, та же технология, что и так нужна NodeBB для realtime-слоя. Если сообщество вырастет до миллионов постов, есть смысл присмотреться к MongoDB — но для большинства форумов на старте разница некритична.
Отдельная особенность именно NodeBB-контейнера: при первом запуске образ сам разворачивает node_modules, собирает клиентские ассеты в build/ и создаёт config.json. Эти артефакты пересчитываются заново при каждом создании контейнера с нуля, поэтому под них обязательно нужны отдельные volume'ы — иначе каждый docker compose up будет заново тянуть все npm-зависимости и пересобирать бандлы по несколько минут.
Схема каталогов на хосте:
nodebb/
├── docker-compose.yml
├── .env
└── volumes/
└── redis/ # данные Redis (посты, пользователи, сессии)
Остальное — node_modules, build и загрузки — удобнее держать в именованных Docker-volume'ах, а не в bind-каталогах: это быстрее на файловых системах вроде OverlayFS и меньше зависит от прав на хосте.
Ресурсы: для форума на несколько сотен активных пользователей достаточно 2 vCPU и 2–4 ГБ RAM. Сборка клиентских ассетов при первом старте и при каждом крупном обновлении — самый прожорливый по памяти момент; на сервере с 1 ГБ без swap она может упасть.
Готовый docker-compose.yml
Создаём рабочую директорию:
mkdir -p nodebb/volumes/redis
cd nodebb
Файл .env:
NODEBB_URL=https://forum.example.com
REDIS_PASSWORD=замените_на_свой_сложный_пароль
Файл docker-compose.yml:
services:
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
volumes:
- ./volumes/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- nodebb
nodebb:
image: nodebb/docker:latest
restart: unless-stopped
depends_on:
redis:
condition: service_healthy
env_file: .env
environment:
NODEBB_URL: ${NODEBB_URL}
NODEBB_PORT: "4567"
DAEMON: "false"
SILENT: "false"
database: redis
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
REDIS_DATABASE: "0"
volumes:
- node_modules:/usr/src/app/node_modules
- build:/usr/src/app/build
- uploads:/usr/src/app/public/uploads
ports:
- "127.0.0.1:4567:4567"
networks:
- nodebb
networks:
nodebb:
driver: bridge
volumes:
node_modules:
build:
uploads:
Официальный образ nodebb/docker при первом запуске сам проходит эквивалент ./nodebb setup, читая переменные окружения вместо интерактивных вопросов — DAEMON: "false" держит процесс на переднем плане, как и требуется для контейнера. Список переменных иногда пополняется между релизами образа, поэтому при переходе на новую мажорную версию стоит свериться с актуальным README на Docker Hub.
Порт 4567 намеренно опубликован только на 127.0.0.1 — снаружи форум должен отдавать обратный прокси с TLS, а не контейнер напрямую.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПервый запуск и создание администратора
docker compose up -d
docker compose logs -f nodebb
Первый старт займёт заметно дольше последующих: контейнер устанавливает npm-зависимости и собирает клиентские бандлы прямо в volume build. Дожидайтесь строки о готовности сервера в логах, прежде чем открывать сайт — если зайти слишком рано, браузер просто получит отказ в соединении.
Когда форум поднялся, зайдите на NODEBB_URL (или временно на http://ip-сервера:4567, если прокси ещё не настроен). Пустой форум показывает экран приветствия и предлагает зарегистрировать первого пользователя — он автоматически получает права администратора. Как и в любой публичной установке: если сервер уже смотрит в интернет без прокси, на время этого шага стоит временно ограничить доступ к порту 4567 через firewall своим IP, чтобы администратором не стал кто-то другой.
HTTPS и WebSocket через обратный прокси
Это критичный момент именно для NodeBB: без проксирования Upgrade-заголовков Socket.IO не сможет держать постоянное соединение, и форум либо откатится на постоянные переподключения, либо вовсе перестанет получать обновления в реальном времени. Конфиг nginx (общая методика настройки — в статье про nginx как обратный прокси):
server {
listen 443 ssl http2;
server_name forum.example.com;
ssl_certificate /etc/letsencrypt/live/forum.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/forum.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:4567;
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;
# Socket.IO держит соединение долго — таймауты по умолчанию его обрывают
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
Если не хочется вручную гонять certbot, Caddy получает и продлевает сертификат сам, а заголовки для WebSocket добавляет по умолчанию (см. Caddy с авто-SSL):
forum.example.com {
reverse_proxy 127.0.0.1:4567
}
После того как прокси заработал, проверьте в Admin Control Panel → Settings → General, что поле «URL» форума указывает на https://, а не на http://. Расхождение — частая причина, когда часть страницы грузится, а Socket.IO-соединение падает с ошибкой mixed content в консоли браузера.
Плагины, темы и мобильный PWA-опыт
Плагины и темы устанавливаются не через файловую систему, а прямо из админки: Admin Control Panel → Extend → Plugins, поиск по каталогу npm-пакетов с префиксом nodebb-plugin- или nodebb-theme-. После установки и активации панель предложит пересобрать клиентские ассеты и перезапустить процесс — оба шага она выполняет сама, вручную заходить в контейнер не требуется. Именно поэтому volume build в docker-compose.yml обязателен: без него результат пересборки исчезнет при следующем пересоздании контейнера.
Мобильный опыт — вторая сильная сторона NodeBB. Манифест PWA и service worker подключены по умолчанию: на телефоне браузер предложит «добавить форум на главный экран», и дальше он открывается как обычное приложение, без строки адреса. Push-уведомления в браузере (не путать с email-уведомлениями, которые работают из коробки) требуют дополнительно сгенерировать VAPID-ключи и включить их в разделе Admin → Settings → Notifications — это отдельная, не обязательная для старта настройка.
Из практичных плагинов, которые почти всегда ставят на старте: nodebb-plugin-emoji (расширенный набор эмодзи), nodebb-plugin-spam-be-gone (базовая антиспам-эвристика для новых аккаунтов) и один из SSO-плагинов, если у вас уже есть внешняя система авторизации.
Резервное копирование и обновление
Бэкапить нужно данные Redis и загруженные пользователями файлы — это два независимых источника, которые нельзя восстановить друг из друга. Простой скрипт для крон-задания:
#!/bin/bash
BACKUP_DIR=/backups/nodebb
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# снимок Redis (RDB) через встроенный механизм сохранения
docker compose exec -T redis redis-cli -a "$REDIS_PASSWORD" --rdb /data/dump.rdb
cp volumes/redis/dump.rdb "$BACKUP_DIR/redis_$DATE.rdb"
# загрузки пользователей — именованный volume, копируем через временный контейнер
docker run --rm -v nodebb_uploads:/data -v "$BACKUP_DIR":/backup alpine \
tar czf "/backup/uploads_$DATE.tar.gz" -C /data .
find "$BACKUP_DIR" -mtime +14 -delete
Имя volume nodebb_uploads зависит от названия каталога проекта — docker compose подставляет его как префикс (docker compose config покажет реальные имена, если сомневаетесь). Общий подход к бэкапу Docker-volume'ов разобран в статье про бэкап Docker volume.
Обновление — стандартный цикл docker compose, но перед ним обязателен свежий бэкап: ./nodebb upgrade внутри образа прогоняет миграции схемы данных, и откатить их без бэкапа Redis нельзя.
# сначала бэкап (см. выше)
docker compose pull nodebb
docker compose up -d nodebb
docker compose logs -f nodebb # следите за завершением миграций и сборки
Первый запуск после обновления образа снова пересобирает клиентские ассеты — это нормально и может занять несколько минут, не прерывайте процесс на этом шаге.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Redis или MongoDB для NodeBB в Docker — что выбрать?
Оба варианта официально поддерживаются ядром. Redis проще для одного сервера и переиспользует уже нужный для Socket.IO движок; MongoDB удобнее для очень крупных форумов и горизонтального масштабирования данных. Для старта на одном VPS хватает Redis — переход на MongoDB позже потребует миграции данных, а не просто смены переменных окружения.
Почему после переезда за nginx пропали реалтайм-обновления?
Почти всегда не проброшены заголовки Upgrade/Connection: upgrade, либо proxy_http_version не выставлен в 1.1. Без них Socket.IO не может установить WebSocket-соединение и либо откатывается на постоянные HTTP-запросы, либо рвётся каждые несколько секунд.
Сколько ресурсов нужно под средний форум?
Для нескольких сотен активных пользователей достаточно 2 vCPU и 2–4 ГБ RAM. Точные цифры сильно зависят от количества и веса плагинов — часть из них добавляет свою нагрузку на сборку и рендер, поэтому ориентируйтесь на этот диапазон и следите за docker stats в первые недели.
Как перенести форум на другой сервер?
Останавливаете стек, копируете volumes/ целиком (или восстанавливаетесь из бэкапа по схеме выше) вместе с именованными volume'ами node_modules, build, uploads, переносите docker-compose.yml и .env, поднимаете docker compose up -d на новом сервере и обновляете DNS-запись.
Чем Docker-вариант отличается от установки NodeBB напрямую на сервер?
Логика та же — тот же движок, тот же мастер настройки под капотом, — но персистентность и обновления устроены иначе: вместо systemd-сервиса и git pull у вас volume'ы и docker compose pull. Пошаговая установка без Docker с systemd-автозапуском разобрана в статье про установку NodeBB на Ubuntu 24.04 — полезно свериться, если решаете, какой путь выбрать.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →