MAATRIX / Блог / Как установить и настроить NATS на VPS

Как установить и настроить NATS на VPS

MAATRIX

Когда микросервисам нужно обмениваться сообщениями, первая мысль — поставить Kafka или RabbitMQ. Но для 3-10 сервисов это избыточно: Kafka требует ZooKeeper (или KRaft-кластер), RabbitMQ тянет Erlang VM и Management-плагин, и оба съедают гигабайты памяти на VPS, где каждый мегабайт на счету. NATS решает ту же задачу — pub/sub, request/reply, очереди — одним статическим бинарником на Go, который стартует за секунду и держит десятки тысяч сообщений в секунду на самом скромном тарифе. Ниже — рабочая установка на чистый VPS: от бинарника до JetStream с персистентностью и TLS.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Установка NATS Server на VPS

NATS не входит в стандартные репозитории Ubuntu/Debian, поэтому ставим бинарник напрямую — это официальный и самый предсказуемый способ. Понадобится VPS с 1 vCPU / 1-2 ГБ RAM для старта — этого достаточно для нескольких тысяч сообщений в секунду при небольшой нагрузке.

Установочный скрипт NATS Inc. ставит nats-server в /usr/local/bin:

curl -sf https://binaries.nats.dev/nats-io/nats-server/v2@latest | sh
sudo mv nats-server /usr/local/bin/
nats-server --version

Если скрипт недоступен (иногда блокируется на VPS в РФ), скачайте релиз вручную с GitHub-страницы проекта nats-io/nats-server под свою архитектуру (amd64/arm64), распакуйте tar.gz и положите бинарник в /usr/local/bin.

Отдельно ставим CLI-клиент nats — им будем проверять публикацию и подписку:

curl -sf https://binaries.nats.dev/nats-io/natscli/nats@latest | sh
sudo mv nats /usr/local/bin/

Создаём пользователя и каталоги, чтобы сервер не работал под root:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin nats
sudo mkdir -p /etc/nats /var/lib/nats/jetstream /var/log/nats
sudo chown -R nats:nats /var/lib/nats /var/log/nats

Для теста хватит и Docker-варианта (docker run -p 4222:4222 nats:2.10-alpine), но в проде systemd-сервис с нативным бинарником проще диагностировать и обновлять — покажу оба пути ниже.

Настройка nats-server.conf

Вся конфигурация NATS — один файл. Начнём с рабочего минимума под одиночный узел с аутентификацией и лимитами:

# /etc/nats/nats-server.conf
server_name: nats-vps-01
listen: 0.0.0.0:4222

http_port: 8222

max_connections: 5000
max_payload: 4MB
max_pending: 64MB

authorization {
  user: app
  password: "$2a$11$XyZ...сгенерированный_bcrypt_хэш"
  timeout: 2
}

logfile: "/var/log/nats/nats-server.log"
log_size_limit: 100MB
max_traced_msg_len: 0

Пароль не храните в открытом виде — генерируйте bcrypt-хэш самим сервером:

nats-server --bcrypt 'my-strong-password'

Результат подставьте в password. Порт 8222 — это HTTP-эндпоинт мониторинга (/varz, /connz, /subz), он не для клиентских подключений, но по умолчанию отвечает всем — закрываем его файрволом позже.

Если сервисов несколько и им не нужно видеть чужой трафик, используйте accounts — встроенную мультитенантность NATS:

accounts {
  ORDERS: {
    users: [ { user: orders_svc, password: "$2a$11$..." } ]
  }
  BILLING: {
    users: [ { user: billing_svc, password: "$2a$11$..." } ]
  }
}

Каждый аккаунт получает изолированное пространство subject'ов — сервис из ORDERS физически не сможет подписаться на темы BILLING, даже если знает их имена.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Запуск через systemd

Юнит для нативного бинарника:

# /etc/systemd/system/nats.service
[Unit]
Description=NATS Server
After=network.target

[Service]
Type=simple
User=nats
Group=nats
ExecStart=/usr/local/bin/nats-server -c /etc/nats/nats-server.conf
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

LimitNOFILE важен: под нагрузкой каждое подключение — это файловый дескриптор, а дефолтные 1024 в Ubuntu кончатся быстрее, чем вы ожидаете.

sudo systemctl daemon-reload
sudo systemctl enable --now nats
sudo systemctl status nats

Проверить, что процесс слушает порт:

ss -tlnp | grep 4222

Если хотите поднять NATS в связке с остальным стеком через Docker Compose, конфиг тот же файл монтируется как volume — общий подход к продакшен-compose разбирал в статье про docker compose для продакшена.

Проверка: publish и subscribe через NATS CLI

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

nats context save vps \
  --server nats://app:my-strong-password@127.0.0.1:4222 \
  --select

Подписываемся на subject в одном терминале:

nats sub "orders.created"

И публикуем сообщение из другого:

nats pub "orders.created" '{"order_id": 4821, "sum": 1500}'

Подписчик мгновенно получает сообщение — задержка на локальной сети обычно укладывается в единицы миллисекунд, но точную цифру для вашего VPS и нагрузки надёжнее измерить самостоятельно через nats bench, готовые бенчмарки из интернета для вашей конфигурации не показательны.

Проверить request/reply (для RPC-паттерна между сервисами):

# сервис-обработчик
nats reply "billing.charge" "OK, processed"

# клиент
nats request "billing.charge" '{"amount": 500}'

Queue-группы — способ распределить нагрузку между несколькими инстансами одного сервиса без дублирования обработки:

nats sub "orders.created" --queue workers

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

Аутентификация и TLS

Пароль в конфиге — минимум. Если сервисы обмениваются данными не только внутри одного VPS (например, между дата-центрами RU и US), трафик должен идти в TLS. Получаем сертификат (Let's Encrypt через certbot, если у вас есть домен, привязанный к IP сервера) и добавляем блок:

tls {
  cert_file: "/etc/nats/certs/fullchain.pem"
  key_file: "/etc/nats/certs/privkey.pem"
  verify: false
  timeout: 3
}

Клиенты подключаются уже через tls:// вместо nats://. Для внутренней связи микросервисов в пределах одного VPS через 127.0.0.1 или приватную сеть TLS избыточен — там достаточно пароля и firewall, но между узлами разных провайдеров или дата-центров не экономьте на шифровании.

Отдельно — сетевой доступ. Порт 4222 должен быть открыт только для тех IP, которым реально нужно подключаться к брокеру:

sudo ufw allow from 10.0.0.0/24 to any port 4222 proto tcp
sudo ufw deny 4222
sudo ufw deny 8222

Порт мониторинга 8222 наружу лучше вообще не открывать — доступ к нему берите через SSH-туннель (ssh -L 8222:localhost:8222 user@vps) или проксируйте локально для Prometheus-экспортёра. Общие принципы настройки правил разобраны в статье про firewall ufw на VPS.

JetStream: персистентность вместо fire-and-forget

Голый NATS — это at-most-once доставка: если подписчика не было онлайн в момент публикации, сообщение потеряно. Для событий, которые нельзя терять (платежи, заказы, аудит-лог), включаем JetStream — встроенный слой персистентности поверх того же брокера, без отдельного сервиса.

Добавляем в конфиг:

jetstream {
  store_dir: "/var/lib/nats/jetstream"
  max_memory_store: 512MB
  max_file_store: 10GB
}

После перезапуска сервера создаём стрим — по сути, персистентный лог сообщений по маске subject'ов:

nats stream add ORDERS \
  --subjects "orders.>" \
  --storage file \
  --retention limits \
  --max-age 168h \
  --max-bytes 5GB \
  --replicas 1

--replicas 1 — для одиночного узла. Если позже добавите ещё два VPS в кластер, поднимите --replicas 3 и получите репликацию с автоматическим failover — но это отдельная тема, кластеризация на старте обычно не нужна.

Consumer с подтверждением обработки (durable, чтобы позиция сохранялась между перезапусками сервиса):

nats consumer add ORDERS billing-worker \
  --filter "orders.created" \
  --ack explicit \
  --pull \
  --max-deliver 5

Теперь, если сервис-подписчик упал на 10 минут, после рестарта он получит все пропущенные сообщения из стрима — вместо того чтобы они молча исчезли, как в обычном pub/sub.

Мониторинг и типичные проблемы

Эндпоинт /varz на порту 8222 отдаёт JSON со всей телеметрией: подключения, память, медленные потребители, ошибки. Быстрая проверка:

curl -s http://127.0.0.1:8222/varz | jq '.mem, .connections, .slow_consumers'

Растущий slow_consumers — сигнал, что какой-то подписчик не успевает вычитывать очередь и NATS начинает его дропать (это осознанное поведение сервера — он не будет копить сообщения в памяти ради одного медленного клиента). Решение — либо ускорить обработчик, либо перевести subject на JetStream с pull-consumer, где скорость чтения контролирует сам клиент.

Для постоянного мониторинга проще всего прометеевский nats-exporter (отдельный маленький бинарник от NATS Inc.), который транслирует /varz в формат Prometheus:

nats-exporter -varz -connz -subz \
  -addr 0.0.0.0:7777 \
  http://localhost:8222

Дальше — стандартный Grafana-дашборд поверх этого экспортёра; общая настройка связки разобрана в статье про Grafana и Prometheus на VPS.

Частая проблема после установки — сервис не может подключиться, хотя порт открыт локально. Обычно причина одна из трёх: файрвол режет входящий трафик именно на 4222 (проверьте ufw status numbered), в конфиге listen смотрит на 127.0.0.1 вместо 0.0.0.0, либо клиент подключается без пароля к серверу с authorization — тогда в логе будет Authorization Violation, а не таймаут. Смотрите journalctl -u nats -f — NATS логирует причину отказа в подключении явно, гадать не приходится.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем NATS отличается от Redis Pub/Sub?

Redis Pub/Sub тоже быстрый, но не хранит сообщения и не имеет очередей с подтверждением — это чистый broadcast. NATS с JetStream добавляет персистентность, replay и consumer groups, оставаясь легче Kafka. Если брокер вам нужен заодно с кэшем — посмотрите на установку Redis на VPS, но для message-очередей это разные инструменты.

Сколько RAM реально нужно NATS?

Сам процесс на простое ест 15-20 МБ. Основной расход памяти — буферы подключений и, при включённом JetStream, max_memory_store из конфига. Для старта достаточно VPS с 1-2 ГБ RAM; точную нагрузку под ваш профиль сообщений замерьте через nats bench.

Нужен ли кластер из нескольких узлов?

Только если критична отказоустойчивость самого брокера. Для одного проекта на старте одного VPS с JetStream и регулярным бэкапом /var/lib/nats/jetstream обычно достаточно — кластеризация добавляет сложность эксплуатации, которая окупается на масштабе.

Как обновить NATS без потери сообщений?

JetStream пишет данные на диск в store_dir, поэтому systemctl restart nats после замены бинарника не теряет данные стримов — сервер перечитывает состояние при старте. Для голого pub/sub без JetStream любой рестарт роняет неподтверждённые сообщения, это ожидаемо.

Можно ли подключаться из другого дата-центра?

Да, но только через TLS и с ограничением по IP на файрволе — открывать 4222 в интернет без шифрования и списка разрешённых адресов не стоит, даже с паролем.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →