Удельта

Пошаговая инструкция · Самостоятельная установка

Как установить Novu на сервер и проверить доставку уведомлений

Пошаговая инструкция для самостоятельной установки. Развернём Novu Community, подключим почтового провайдера и вызовем уведомление через API. Разделим адреса панели, API и вебсокетов, закроем регистрацию и сохраним ключи вместе с базой.

Настройка уведомлений: одно событие распределяется по почтовому, мобильному и веб-каналам

Что подготовить и как читать инструкцию #

Novu принимает события вашего приложения и выполняет workflow: например, отправляет письмо или создаёт уведомление внутри интерфейса. Community поддерживает визуальные и программные workflow. Облачные SSO, MFA, RBAC, произвольные окружения и расширенное отслеживание доставки не следует считать частью этой установки. В актуальной матрице Community указан один участник команды, поэтому сначала оцените, подходит ли такое администрирование проекту.

Подготовьте Ubuntu 26.04 LTS, Docker Engine, Compose v2 и Nginx. Для всех компонентов на одной машине предусмотрите минимум около 4 vCPU и 12 ГБ памяти: официальная рекомендация выделяет 8 ГБ сервисам Novu и отдельно память MongoDB и Redis. Это ориентир документации, а не выполненное нами испытание; запас на SSD нужен для базы и очередей.

Команды выполняйте в терминале сервера после подключения по SSH, если шаг не указывает другое место. sudo даёт команде права администратора. Действия в браузере выполняйте на своём компьютере. Домены, IP-адреса и значения ВАШ_ПАРОЛЬ из примеров заменяйте своими до выполнения команды.

Двигайтесь по одному шагу и проверяйте результат перед следующим. Блок с <<EOF или другим именем завершения копируйте целиком: он записывает содержимое одного файла. При работе в nano сохраняйте файл клавишами Ctrl+O, Enter и выходите Ctrl+X. Если прервали SSH-сеанс, снова перейдите в указанный каталог; переменные предыдущего сеанса потребуется задать заново.

Настройка внешнего доступа использует обратный прокси Nginx и Certbot для Nginx. Приложение остаётся доступным на локальном порту; снаружи открыт его HTTPS-домен.

Шаг 1. Создайте каталог Novu #

Компоненты уведомлений будут описаны в ~/apps/novu. Перейдите в этот каталог перед следующими командами.

Создайте каталог Novu
mkdir -p ~/apps/novu
cd ~/apps/novu
umask 077

Текущий каталог — ~/apps/novu.

Шаг 2. Скачайте файлы выбранного релиза #

Загрузим официальный Compose и пример переменных из тега v3.19.0. Используем этот комплект, а не меняющуюся ветку latest.

Скачайте файлы выбранного релиза
curl -fL https://raw.githubusercontent.com/novuhq/novu/v3.19.0/docker/community/docker-compose.yml -o compose.yaml
curl -fL https://raw.githubusercontent.com/novuhq/novu/v3.19.0/docker/community/.env.example -o .env

Оба файла скачаны без ошибок HTTP.

Шаг 3. Заполните ключи и адреса новой установки #

Скрипт ниже меняет только перечисленные параметры .env: создаёт секреты и задаёт три внешних адреса. До копирования замените novu.example.com, novu-api.example.com и novu-ws.example.com своими доменами. STORE_ENCRYPTION_KEY защищает сохранённые реквизиты провайдеров. Не запускайте генератор повторно поверх рабочей установки.

Заполните ключи и адреса новой установки
python3 - <<'PATCH'
from pathlib import Path
import secrets
p = Path('.env')
updates = {
 'JWT_SECRET': secrets.token_hex(32),
 'STORE_ENCRYPTION_KEY': secrets.token_hex(16),
 'NOVU_SECRET_KEY': secrets.token_hex(32),
 'MONGO_INITDB_ROOT_PASSWORD': secrets.token_hex(32),
 'NODE_ENV': 'production',
 'HOST_NAME': 'https://novu.example.com',
 'API_ROOT_URL': 'https://novu-api.example.com',
 'VITE_API_HOSTNAME': 'https://novu-api.example.com',
 'VITE_WEBSOCKET_HOSTNAME': 'https://novu-ws.example.com',
 'FRONT_BASE_URL': 'https://novu.example.com',
 'S3_LOCAL_STACK': '',
 'DISABLE_USER_REGISTRATION': 'false',
}
lines = [line for line in p.read_text().splitlines() if line.split('=', 1)[0] not in updates]
lines.extend(key + '=' + value for key, value in updates.items())
p.write_text('\n'.join(lines) + '\n')
PATCH

В .env нет прежних пустых секретов; все три домена ваши.

Шаг 4. Проверьте настройки и внешнее хранилище #

Откройте .env. По исходной конфигурации задайте реквизиты реального S3-хранилища для вложений; LocalStack не используем как рабочее хранилище. Не заменяйте уже созданные ключи и пароль MongoDB.

Проверьте настройки и внешнее хранилище
chmod 600 .env
nano .env

Поля адресов, ключей и S3 заполнены; файл защищён правами 600.

Шаг 5. Закройте внутренние порты и закрепите версии #

Скрипт изменяет только compose.yaml: образы Novu приводятся к 3.19.0, Redis получает постоянный том, HTTP/WS-порты привязываются к localhost. Не меняем домены, заданные в .env.

Закройте внутренние порты и закрепите версии
python3 - <<'PATCH'
from pathlib import Path
p = Path('compose.yaml')
s = p.read_text().replace(':3.18.0"', ':3.19.0"')
s = s.replace('image: "redis:alpine"', 'image: "redis:7-alpine"\n    command: [redis-server, --appendonly, "yes", --appendfsync, everysec]\n    volumes:\n      - redis_data:/data')
s = s.replace('- ${API_PORT}:${API_PORT}', '- "127.0.0.1:${API_PORT}:${API_PORT}"')
s = s.replace('- ${WS_PORT}:${WS_PORT}', '- "127.0.0.1:${WS_PORT}:${WS_PORT}"')
s = s.replace('- 4000:4000', '- "127.0.0.1:4000:4000"')
s = s.replace('      IS_SELF_HOSTED: ${IS_SELF_HOSTED}', '      IS_SELF_HOSTED: ${IS_SELF_HOSTED}\n      DISABLE_USER_REGISTRATION: ${DISABLE_USER_REGISTRATION}')
s = s.replace('volumes:\n  mongodb:', 'volumes:\n  redis_data:\n  mongodb:')
p.write_text(s)
PATCH

При просмотре compose.yaml внешний интерфейс не публикует порты 3000, 3002 и 4000 напрямую.

Шаг 6. Проверьте конфигурацию #

Compose проверит файл и параметры. Ошибка отсутствующей переменной означает, что нужно вернуться к .env.

Проверьте конфигурацию
docker compose config --quiet

config --quiet завершился без ошибки.

Шаг 7. Скачайте образы #

Загрузим компоненты API, панели, WebSocket и исполнителя. Они должны быть одной согласованной версии.

Скачайте образы
docker compose pull

pull завершился успешно.

Шаг 8. Запустите сервисы #

Первый запуск подготавливает MongoDB и приложение; дождитесь окончания команды.

Запустите сервисы
docker compose up -d

Контейнеры созданы, затем проверим их готовность.

Шаг 9. Сохраните сайт Nginx #

Установите Nginx и Certbot по подготовке Ubuntu, если ещё не установили. Откройте sudo nano /etc/nginx/sites-available/novu и вставьте файл ниже. Замените все домены своими. Замените 203.0.113.10 внешним IP своего рабочего компьютера: ограничение действует только на панель, а проверка сертификата остаётся доступной. Nginx передаёт приложению домен, адрес клиента и протокол; Upgrade и Connection сохраняют WebSocket. До получения сертификата условие $scheme блокирует обычные HTTP-запросы кодом 403, чтобы вход не происходил без шифрования.

Файл /etc/nginx/sites-available/novu
map $http_upgrade $novu_connection_upgrade {
    default upgrade;
    "" close;
}

server {
    listen 80;
    server_name novu.example.com;
    client_max_body_size 100m;
    location / {
        if ($scheme = http) { return 403; }
        allow 203.0.113.10;
        deny all;
        proxy_pass http://127.0.0.1:4000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $novu_connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
    }
}

server {
    listen 80;
    server_name novu-api.example.com;
    client_max_body_size 100m;
    location / {
        if ($scheme = http) { return 403; }
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $novu_connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
    }
}

server {
    listen 80;
    server_name novu-ws.example.com;
    client_max_body_size 100m;
    location / {
        if ($scheme = http) { return 403; }
        proxy_pass http://127.0.0.1:3002;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $novu_connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
    }
}

Сохраните Ctrl+O, Enter, Ctrl+X. В файле пока нет путей к сертификатам: Nginx сможет проверить его до выпуска HTTPS.

Шаг 10. Подключите сайт и проверьте HTTP #

Ссылка подключает сохранённый сайт. nginx -t проверяет все настройки сервера; && разрешает перечитать их только при успешной проверке. curl проверяет ответ для вашего домена. При ошибке остановитесь, исправьте указанную строку и повторите проверку.

Подключите сайт и проверьте HTTP
sudo ln -sfn /etc/nginx/sites-available/novu /etc/nginx/sites-enabled/novu
sudo nginx -t && sudo systemctl reload nginx
curl -I http://novu.example.com/

Ожидается successful от nginx -t и HTTP 403 для обычного запроса: до HTTPS это намеренная блокировка. DNS должен указывать на сервер, TCP 80/443 — быть доступен у провайдера. Ничего не вводите в форму входа по HTTP.

Шаг 11. Получите сертификат и включите HTTPS #

Каждое имя из команды должно указывать на этот сервер. Certbot проверит домены, сам добавит сертификат в сайт Nginx и включит перенаправление HTTP → HTTPS. Укажите свою почту при запросе и подтвердите условия Let’s Encrypt. Это отдельное действие после успешной проверки HTTP.

Получите сертификат и включите HTTPS
sudo /snap/bin/certbot --nginx -d novu.example.com -d novu-api.example.com -d novu-ws.example.com --redirect

Certbot сообщил об успешной установке. Откройте HTTPS-адрес со своего компьютера: браузер не должен предупреждать о сертификате. Для закрытой панели используйте разрешённый IP. При ошибке исправьте DNS, в том числе AAAA, либо доступ к TCP 80; не повторяйте запросы выпуска подряд.

Шаг 12. Проверьте продление сертификата #

Certbot из snap создаёт службу автоматического продления. Dry-run выполняет пробное продление: настоящие сертификаты не заменяются. Затем проверьте, что таймер планирует следующий запуск. Сохраняйте доступ к TCP 80 для следующих проверок домена.

Проверьте продление сертификата
sudo /snap/bin/certbot renew --dry-run
systemctl list-timers --all 'snap.certbot.renew*'

Пробное продление успешно, у таймера есть следующий запуск. Если тест не прошёл, проверьте /var/log/letsencrypt/letsencrypt.log; сначала исправьте причину. После этого можно создавать учётную запись и приглашать пользователей.

Шаг 13. Проверьте API и обработчик #

Состояние контейнеров и health-check показывают готовность; журнал worker важен для фактической отправки уведомлений.

Проверьте API и обработчик
docker compose ps
curl -f http://127.0.0.1:3000/v1/health-check
docker compose logs --tail=80 api worker ws

API отвечает, worker/ws не перезапускаются.

Шаг 14. Создайте владельца организации #

В браузере откройте панель, зарегистрируйте первую учётную запись и организацию. Сохраните выбранные реквизиты. Подготовка остальных пользователей будет выполняться через согласованный доступ.

Владелец входит и видит настройки организации.

Шаг 15. Закройте свободную регистрацию #

В .env измените DISABLE_USER_REGISTRATION на true, сохранив ключи. Пересоздайте API, чтобы он прочитал новое значение.

Закройте свободную регистрацию
# В .env установите DISABLE_USER_REGISTRATION=true.
nano .env
docker compose up -d --force-recreate api

Посторонняя регистрация отклоняется; существующий владелец входит.

Шаг 16. Подготовьте тестовое уведомление #

Подключите SMTP/email-провайдера в выбранном окружении, создайте workflow с идентификатором из примера ниже и subscriber с собственным email. Секрет API относится к этому же окружению. Если в запросе другой идентификатор, замените его реальным.

Workflow опубликован в тестовом окружении; адрес получателя ваш.

Шаг 17. Отправьте событие из терминала #

Введите API-ключ по скрытому запросу. curl отправит событие workflow, а unset уберёт ключ из текущего сеанса. Не записывайте ключ в публичный код браузера.

Отправьте событие из терминала
read -rsp 'API-ключ окружения Novu: ' NOVU_API_KEY
printf '\n'
curl -f https://novu-api.example.com/v1/events/trigger \
  -H "Authorization: ApiKey $NOVU_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"name":"server-check","to":{"subscriberId":"server-check-owner","email":"owner@example.com"},"payload":{}}'
unset NOVU_API_KEY

API принял событие; в Activity видна обработка и на тестовый ящик пришло письмо.

Шаг 18. Остановите изменения перед копией #

Создадим закрытый каталог и остановим API/worker/ws. MongoDB останется доступной для выгрузки.

Остановите изменения перед копией
umask 077
backup_dir="$HOME/backups/novu/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$backup_dir"
docker compose stop api worker ws

Компоненты приложения остановлены; переменная backup_dir задана в этом SSH-сеансе.

Шаг 19. Скопируйте MongoDB #

В базе находятся подписчики, workflow, настройки и история. mongodump читает реквизиты из контейнера.

Скопируйте MongoDB
docker compose exec -T mongodb sh -c 'exec mongodump --username "$MONGO_INITDB_ROOT_USERNAME" --password "$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --db novu-db --archive --gzip' > "$backup_dir/database.archive.gz"

Архив базы создан без ошибки.

Шаг 20. Сохраните ключи и описание установки #

Скопируйте .env и Compose вместе с базой. Объекты S3 копируются средствами отдельного хранилища; один mongodump их не сохраняет.

Сохраните ключи и описание установки
cp .env compose.yaml "$backup_dir/"

Ключи, база и копия S3 доступны вне установленного сервера.

Шаг 21. Запустите Novu и проверьте копию #

Верните API/worker/ws и повторите тестовое уведомление. Проверку восстановления проводите в отдельном окружении с тестовым провайдером, чтобы не отправлять рабочие уведомления.

Запустите Novu и проверьте копию
docker compose start api worker ws

Тестовое письмо снова доставляется; копия возвращает workflow и подписчика.

Если результат шага отличается #

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

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

Настройки внешнего доступа храните вместе с копией приложения: /etc/nginx/sites-available/novu и /etc/letsencrypt содержат сайт и сертификаты с закрытыми ключами. Архивируйте их с sudo в закрытое хранилище. После восстановления подключите сайт через sites-enabled, выполните sudo nginx -t, затем перечитайте Nginx. Для ошибки 502 сначала проверьте локальное приложение и /var/log/nginx/error.log; для сертификата — /var/log/letsencrypt/letsencrypt.log и таймер продления.

Обсудить установку и настройку

Материал был полезен?

Сообщить об ошибке или задать вопрос редакции

Сообщение увидит редакция. Не указывайте пароли и личные данные. Текст удаляется через 180 дней.

О материале

ИнфраструктураРуководствоЗадача: установитьУровень: практикаNovu

Последнее обновление:

Обсуждение

Комментарии проходят подтверждение адреса и проверку редакцией.