VPSРейтинг
Self-hosted23 августа 2026 · 19 мин

Nezha на VPS: мониторинг всех своих серверов на одной странице

Когда серверов становится больше двух, начинается бардак: у каждого своя панель хостера, свой счётчик трафика и свой пароль. Nezha собирает всё это в одну вкладку и, главное, сам пишет в Telegram, когда сервер упал или когда месячный пакет трафика подходит к концу.

Задача: несколько серверов и ни одной общей картины

Типичная ситуация человека, который несколько лет что-то арендует. Один VPS в России под сайт, один в Германии под VPN, один совсем дешёвый в Финляндии под бота и ещё старый где-то, про который вы уже забыли, но деньги за него списываются. Четыре разные панели управления, четыре логина, четыре способа посмотреть нагрузку.

Из-за этого регулярно случаются три вещи. Первая: сервер упал, а вы узнаёте об этом через час от пользователя. Вторая: на диске кончилось место — обычно из-за логов или бэкапов, которые никто не чистил, — и приложение молча перестало работать. Третья, самая обидная и самая частая у дешёвых зарубежных хостеров: кончился месячный лимит трафика. Дальше в зависимости от тарифа хостер либо режет скорость до неприличной, либо выставляет счёт за перерасход, либо просто выключает сервер.

Идея Nezha в одном предложении

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

Nezha (哪吒 — имя персонажа китайской мифологии) развивается с 2019 года и живёт на GitHub под лицензией Apache 2.0. К августу 2026 у репозитория около 10 300 звёзд, актуальная версия панели — 2.3.7 от 17 августа 2026, агента — 2.3.3 от 12 августа. Релизы выходят буквально каждую неделю.

Все команды, конфиги и сообщения об ошибках ниже проверены на реально развёрнутой установке версии 2.3.7 с агентом 2.3.3 — включая работу через Nginx с сертификатом и подключение агента по HTTPS.

Nezha или что-то другое: короткая развилка

Мониторинг — область, где легко взять слишком тяжёлый инструмент и бросить его через неделю. Четыре варианта и когда какой брать (про три из них у нас есть отдельные статьи):

ИнструментЗа чем следитКогда брать
Uptime Kumaсайты и порты снаружи, сертификаты«жив ли мой сайт» — и больше ничего не нужно
Beszelресурсы машины и контейнеры Dockerодин-два домашних сервера, нужна простота
Nezhaресурсы, аптайм, трафик за период, проверки сайтов с каждого сервера3–10 арендованных VPS, часть с лимитом трафика
Prometheus + Grafanaлюбые метрики, включая метрики приложенийнужны свои метрики, запросы и сложные дашборды

Ниша Nezha — ровно между «слишком просто» и «слишком сложно». Prometheus с Grafana умеют больше, но там нужно самому придумать экспортеры, метки, запросы и дашборды, а потом всё это поддерживать. Nezha даёт фиксированный набор из коробки: поставил агент — сервер появился на странице со всеми графиками. За это платите отсутствием гибкости: своих метрик сюда не завезти.

Как это устроено

Две части. На одном сервере — панель (dashboard): веб-интерфейс, база SQLite и хранилище графиков. На каждом наблюдаемом сервере — агент: одна программа на 18 МБ, которая раз в три секунды отправляет панели состояние машины.

Соединение всегда начинает агент: он сам подключается к панели и держит соединение открытым. Это удобно — на наблюдаемых серверах не нужно открывать ни одного входящего порта. Открытый порт нужен только у панели.

Важная особенность: всё на одном порту

Начиная со второго поколения Nezha веб-интерфейс и канал агентов живут на одном и том же порту — по умолчанию 8008. Браузер ходит туда обычным HTTP, а агенты — по протоколу gRPC, который работает поверх HTTP/2. Отсюда следует главное практическое правило всей статьи: обратный прокси перед панелью обязан уметь HTTP/2 и gRPC. Если этого нет, панель в браузере откроется идеально, а агенты не подключатся никогда. Ниже разберём это подробно — там же лежит самая частая ошибка при установке.

По той же причине адрес для агентов нельзя прятать за CDN: обычный CDN не пропускает gRPC-соединения либо рвёт их по таймауту. Об этом прямо предупреждает и официальная документация. Если очень хочется CDN для красивой публичной страницы, заводите два домена — один для браузеров через CDN, второй для агентов напрямую.

Что понадобится

  • Отдельный VPS под панель. Хватает 1 vCPU, 1 ГБ памяти и 10–15 ГБ диска — измеренный расход самой панели ниже 100 МБ памяти. Брать отдельную машину, а не подселять панель к боевым, стоит по простой причине: мониторинг, который падает вместе с наблюдаемым сервером, бесполезен ровно тогда, когда нужен.
  • Ubuntu 24.04 LTS на этом сервере (команды ниже — под неё; на 22.04 всё то же самое).
  • Домен и A-запись на IP сервера панели. В статье используется nezha.example.com — подставляйте свой. Домен нужен обязательно: без него не будет сертификата, а без сертификата секрет агента полетит по сети открытым текстом.
  • Наблюдаемые серверы — любые машины на Linux, macOS или Windows, к консоли которых у вас есть доступ. Ничего входящего на них открывать не нужно.

Проверьте, что A-запись уже разошлась, — иначе certbot не выдаст сертификат:

на своём компьютере
dig +short nezha.example.com @8.8.8.8

В ответ должен прийти IP сервера панели. Если пусто — подождите, записи расходятся от нескольких минут до часа. Если команды dig под рукой нет, подойдёт любой онлайн-сервис проверки DNS.

Шаг 1. Установка панели

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

Ставим Docker на сервер панели:

Docker + плагин compose
sudo apt update
curl -fsSL https://get.docker.com | sudo sh

Создаём каталог. Путь /opt/nezha/dashboard — тот же, что использует официальный установщик, так что документация проекта будет совпадать с вашей установкой:

каталог
sudo mkdir -p /opt/nezha/dashboard/data
cd /opt/nezha/dashboard

Первый файл — описание контейнера:

sudo nano /opt/nezha/dashboard/docker-compose.yaml
services:
  dashboard:
    image: ghcr.io/nezhahq/nezha:v2.3.7
    container_name: nezha-dashboard
    restart: always
    ports:
      - "127.0.0.1:8008:8008"
    volumes:
      - ./data:/dashboard/data

Префикс 127.0.0.1 в строке портов обязателен. Nezha стартует с учётной записью admin и паролем admin, без всякого мастера начальной настройки: панель полностью работоспособна с первой секунды. Если опубликовать порт наружу, у вас будет открытый в интернет административный интерфейс со стандартным паролем. Строка выше говорит Docker пускать в контейнер только с самого сервера.

Второй файл — конфигурация панели. Он должен лежать именно в подкаталоге data:

sudo nano /opt/nezha/dashboard/data/config.yaml
listen_port: 8008
site_name: "Мои серверы"
language: ru_RU
location: Europe/Moscow

# адрес, по которому агенты будут подключаться к панели
install_host: nezha.example.com:443
tls: true

# реальный IP агента берём из заголовка, который проставит Nginx
agent_real_ip_header: nz-realip

# хранилище истории — без него не будет графиков за 7 и 30 дней
tsdb:
  data_path: "data/tsdb"
  retention_days: 30
  min_free_disk_space_gb: 1
  max_memory_mb: 256

Четыре места здесь неочевидны, и каждое решает реальную проблему:

  • location: Europe/Moscowпо умолчанию Nezha живёт по Шанхаю, и это не косметика. От этого значения зависит, в котором часу сработают задачи по расписанию. Часовой пояс на самих графиках берётся из браузера, тут всё в порядке.
  • install_host и tls: true — адрес и режим подключения агентов. Мы сразу указываем домен и порт 443, потому что агенты будут ходить через Nginx по HTTPS. Эти же поля есть в интерфейсе: «Системные настройки» → «Адрес подключения агента» и «Использовать TLS для подключения агента».
  • agent_real_ip_header: nz-realip — без этой строки панель будет считать, что все ваши серверы находятся по одному адресу: адресу самого Nginx. Мы это проверили: до настройки заголовка в карточке сервера светился внутренний IP прокси, после — реальный адрес агента.
  • Блок tsdbхранилище истории по умолчанию выключено. Пока его нет, на странице сервера доступен только режим «сейчас», а вкладки «1 день», «7 дней» и «30 дней» заблокированы. Внутри — встроенная VictoriaMetrics, отдельно ставить ничего не нужно.

Запускаем и смотрим журнал:

старт
cd /opt/nezha/dashboard
sudo docker compose up -d
sudo docker compose logs --tail 20

В журнале должны быть две строки — про хранилище и про запуск:

как выглядит успешный старт
NEZHA>> TSDB initialized successfully
NEZHA>> Dashboard::START ON :8008

Если вместо первой строки написано TSDB is disabled (tsdb.data_path not configured) — блок tsdb не попал в конфиг: проверьте отступы (два пробела) и то, что файл лежит в data/config.yaml, а не рядом с docker-compose.yaml.

Шаг 2. Первый вход и смена пароля

Порт закрыт от интернета, а пароль пока стандартный — значит, войти нужно так, чтобы наружу ничего не открывать. Для этого есть SSH-туннель: одна команда на вашем компьютере, которая пробрасывает порт сервера на ваш локальный.

на своём компьютере, окно оставить открытым
ssh -L 8008:127.0.0.1:8008 root@IP_СЕРВЕРА

Пока это окно открыто, откройте в браузере http://127.0.0.1:8008/dashboard — это административная часть панели. Логин и пароль: admin / admin.

Первым делом — пароль. Нажмите на аватар в правом верхнем углу, выберите «Профиль» (Profile), заполните «Старый пароль» и «Новый пароль», нажмите «Обновить профиль». Пароль берите длинный, от 18 символов: панель Nezha — это root-доступ ко всем серверам, которые вы к ней подключите.

Интерфейс должен быть на русском — это даёт строка language: ru_RU из конфига. Отдельные новые пункты перевод ещё не догнал и они остаются английскими. Язык при желании переключается и вручную: аватар → «Язык».

Туннель после этого можно закрывать (Ctrl+C в том окне) — дальше панель будет доступна по домену.

Шаг 3. Домен, Nginx и HTTPS

Ставим веб-сервер и клиент Let's Encrypt:

установка
sudo apt install -y nginx certbot python3-certbot-nginx

Создаём конфиг сайта. Замените nezha.example.com на свой домен:

sudo nano /etc/nginx/sites-available/nezha
upstream nezha_dashboard {
    server 127.0.0.1:8008;
    keepalive 512;
}

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

    underscores_in_headers on;

    # канал агентов: gRPC
    location ^~ /proto.NezhaService/ {
        grpc_set_header Host $host;
        grpc_set_header nz-realip $remote_addr;
        grpc_read_timeout 600s;
        grpc_send_timeout 600s;
        grpc_socket_keepalive on;
        grpc_buffer_size 4m;
        client_max_body_size 10m;
        grpc_pass grpc://nezha_dashboard;
    }

    # живое обновление страницы, терминал и файлы: веб-сокет
    location ~* ^/api/v1/ws/(server|terminal|file)(.*)$ {
        proxy_pass http://127.0.0.1:8008;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header nz-realip $remote_addr;
        proxy_set_header Origin https://$host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    # всё остальное: обычный веб-интерфейс
    location / {
        proxy_pass http://127.0.0.1:8008;
        proxy_set_header Host $host;
        proxy_set_header nz-realip $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
        proxy_max_temp_file_size 0;
    }
}

Что здесь важно и почему именно так:

  • Три блока location, а не один. Агенты ходят по адресу /proto.NezhaService/ и требуют grpc_pass — обычный proxy_pass их не пропустит. Веб-сокет по /api/v1/ws/ нужен, чтобы цифры на странице обновлялись сами и работал встроенный терминал. Всё прочее — обычное проксирование.
  • underscores_in_headers on; — Nginx по умолчанию выбрасывает заголовки, в имени которых есть подчёркивание, а агент передаёт учётные данные именно такой парой: client_secret и client_uuid. Свежие версии для надёжности дублируют их и в варианте через дефис, так что без этой строки, скорее всего, тоже заработает — но она стоит в официальном конфиге проекта, ничего не ломает и страхует от старых агентов.
  • nz-realip во всех трёх блоках — тот самый заголовок, который мы указали в конфиге панели. Благодаря ему в карточках серверов видны их настоящие адреса.
  • keepalive 512 в блоке upstream — соединения агентов держатся часами, и без пула Nginx будет постоянно их переустанавливать.

Включаем конфиг и открываем порты. Файрвол настраиваем до выпуска сертификата: Let's Encrypt проверяет домен обращением на 80-й порт, и если он закрыт, сертификата не будет.

включение конфига и файрвол
sudo ln -s /etc/nginx/sites-available/nezha /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Теперь сертификат:

HTTPS
sudo certbot --nginx -d nezha.example.com

Certbot спросит почту, попросит согласиться с условиями и предложит включить перенаправление с HTTP на HTTPS — соглашайтесь. Он сам допишет в конфиг блок с сертификатом и настроит автопродление.

Обязательный шаг, о котором забывают все: включить HTTP/2

Certbot добавляет строку listen 443 ssl; # managed by Certbot без HTTP/2. Панель в браузере после этого работает прекрасно, а агенты не подключатся вообще никогда: gRPC живёт только поверх HTTP/2. Мы специально воспроизвели эту ситуацию, и в журнале агента она выглядит так:

transport: authentication handshake failed: remote error: tls: no application protocol

Лечится дописыванием одного слова.

Откройте sudo nano /etc/nginx/sites-available/nezha и найдите строку, которую дописал certbot. Допишите в неё одно слово — http2:

/etc/nginx/sites-available/nezha
# было:
listen 443 ssl; # managed by Certbot

# стало:
listen 443 ssl http2; # managed by Certbot

Если рядом есть такая же строка для IPv6 — listen [::]:443 ssl ipv6only=on; — допишите http2 и в неё. Затем проверьте и перезагрузите:

проверка
sudo nginx -t
sudo systemctl reload nginx

На Nginx версии 1.25.1 и новее команда nginx -t выдаст предупреждение the "listen ... http2" directive is deprecated. Это именно предупреждение, а не ошибка: конфиг рабочий, и мы это проверили. Если предупреждение раздражает, уберите http2 из строки listen и добавьте отдельной строкой http2 on; внутри блока server — но только на 1.25.1 и новее; в Nginx из репозитория Ubuntu 24.04 (это версия 1.24) такой директивы ещё нет и конфиг не запустится.

Теперь две проверки, которые надо сделать до того, как идти ставить агенты. Первая — что сайт вообще отдаётся по HTTP/2:

проверка 1: включён ли HTTP/2
curl -s -o /dev/null -w 'HTTP-версия: %{http_version}\n' https://nezha.example.com/

Должно быть HTTP-версия: 2. Если 1.1 — слово http2 в строку listen не попало или Nginx не перезагрузился, и агенты не подключатся.

Вторая — что адрес, по которому стучатся агенты, доходит до нужного обработчика:

проверка 2: на месте ли блок gRPC
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' \
  -X POST https://nezha.example.com/proto.NezhaService/ \
  -H 'Content-Type: application/grpc'

Ожидаемый ответ — 200 application/grpc. Если пришло 404 text/html, значит в конфиге потерян или неверно записан блок location ^~ /proto.NezhaService/. Обратите внимание: вторая проверка проходит успешно и без HTTP/2 — Nginx примет запрос по версии 1.1 и сам переведёт его в gRPC. Именно поэтому нужны обе, и первая важнее.

Откройте https://nezha.example.com/dashboard и убедитесь, что вход работает по домену. Если вы предпочитаете Caddy, он умеет и HTTPS сам, и h2c из коробки — конфиг для него есть в документации Nezha, а про сам Caddy у нас есть отдельная статья.

Шаг 4. Подключаем первый сервер

Адрес подключения агентов мы уже задали в конфиге, так что готовая команда установки лежит прямо в интерфейсе. Проверить настройку можно в «Системные настройки» → «Адрес подключения агента [домен/IP:порт]»: там должно быть nezha.example.com:443, а галочка «Использовать TLS для подключения агента» — включена.

Дальше на странице «Сервер» нажмите кнопку «Команда установки» и выберите Linux — команда скопируется в буфер обмена. Выглядит она так (секрет у вас будет свой):

выполнить на наблюдаемом сервере
curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.sh -o agent.sh \
  && chmod +x agent.sh \
  && env NZ_SERVER=nezha.example.com:443 NZ_TLS=true NZ_CLIENT_SECRET=ВАШ_СЕКРЕТ ./agent.sh

Скрипт кладёт агент в /opt/nezha/agent/, создаёт рядом файл config.yml и регистрирует службу systemd с именем nezha-agent.

Скрипт ставит службу, но не запускает её

Внутри он вызывает установку службы, которая создаёт юнит и включает автозапуск, но команду старта не выполняет. Пишет при этом бодрое nezha-agent successfully installed — и человек ждёт сервер в панели, а его нет. Запустите агент сами:

сразу после установки
sudo systemctl enable --now nezha-agent

Через несколько секунд сервер появится в панели сам — со случайным именем вроде talented-caiman. Нажмите на карандаш и переименуйте во что-то понятное.

Проверить агент на месте:

на наблюдаемом сервере
sudo systemctl status nezha-agent
sudo journalctl -u nezha-agent -n 30 --no-pager

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

Если сервер в России и GitHub недоступен

Скрипт качает и сам себя, и бинарник агента с github.com. Когда доступа туда нет, установка молча падает на скачивании. Обходной путь — принести бинарник любым удобным способом (например, скачать на машине, где GitHub открывается, и скопировать через scp) и зарегистрировать службу вручную:

ручная установка агента
sudo mkdir -p /opt/nezha/agent
# положите распакованный nezha-agent в /opt/nezha/agent/ и дайте права
sudo chmod +x /opt/nezha/agent/nezha-agent

sudo env NZ_SERVER=nezha.example.com:443 \
         NZ_TLS=true \
         NZ_CLIENT_SECRET=ВАШ_СЕКРЕТ \
         /opt/nezha/agent/nezha-agent service -c /opt/nezha/agent/config.yml install

sudo systemctl enable --now nezha-agent

Команда service install сама создаст config.yml из переменных окружения и юнит systemd — это ровно то, что делает официальный скрипт на последнем шаге. Архивы под все архитектуры лежат в разделе Releases репозитория nezhahq/agent, для обычного VPS нужен nezha-agent_linux_amd64.zip.

Что видно в панели

По каждому серверу: загрузка процессора, занятая память и swap, занятый диск, средний load за 1/5/15 минут, число процессов, количество TCP- и UDP-соединений, скорость приёма и отдачи прямо сейчас и — то, ради чего всё затевалось — суммарный трафик. Плюс аптайм, модель процессора, дистрибутив с версией, архитектура, тип виртуализации и флаг страны.

Клик по карточке открывает страницу сервера с графиками. Режимы «1 день», «7 дней» и «30 дней» работают только при включённом хранилище истории — мы включили его блоком tsdb на первом шаге.

Отдельно стоит заглянуть в раздел «Сервис». Там задаются проверки доступности: HTTP GET по адресу сайта, ICMP Ping по домену или IP, TCPing по паре адрес-порт. Особенность в том, что проверку выполняют сами агенты, каждый из своей страны, — и на вкладке «Network» на странице сервера видно, как из разных точек отличается задержка до одной и той же цели. Для HTTPS-адресов Nezha заодно следит за сроком сертификата и предупреждает, когда он подходит к концу.

Чтобы трафик считался честно

По умолчанию агент складывает трафик всех сетевых интерфейсов. На сервере с Docker, WireGuard или туннелем это даёт цифры заметно больше тех, что считает хостер: локальные интерфейсы попадают в общий котёл. Лечится списком разрешённых интерфейсов. Посмотрите имена через ip -br link и оставьте только внешний:

/opt/nezha/agent/config.yml
nic_allowlist:
  eth0: true

Рядом работает такой же список для дисков — hard_drive_partition_allowlist, простой список разделов. Он пригождается, когда в «занятом месте» учитывается что-то лишнее. После правки файла: sudo systemctl restart nezha-agent. То же самое можно сделать не заходя на сервер — в панели у каждого сервера есть кнопка «Редактировать конфигурацию сервера», агент применит настройки примерно через 10 секунд.

Шаг 5. Алерт «трафик заканчивается» — главное, ради чего это ставят

Дешёвые зарубежные VPS почти всегда идут с месячным лимитом: 500 ГБ, 1 ТБ, 2 ТБ. Пока лимит не выбран, о нём никто не думает; когда выбран — сервер режут или выставляют счёт. Nezha умеет предупредить заранее, и настраивается это за пять минут.

Правила живут в разделе «Уведомление», на вкладке «Правила тревог». Нажмите кнопку добавления — откроется окно «Создать правила оповещений». Писать JSON руками не нужно: в форме есть конструктор — выпадающий список типа и поля под выбранный тип. Заполняем так:

ПолеЗначениеЧто это
Типtransfer_out_cycleисходящий трафик за расчётный период
max966367641600порог в байтах — здесь 900 ГБ
cycle_start2026-08-01T00:00:00+03:00начало первого периода, с часовым поясом
cycle_interval1длина периода
cycle_unitmonthединица периода: раз в месяц
ОхватMonitor all serversследить за всеми серверами (пункт пока без перевода)

То же самое можно вставить одним куском в поле «Advanced JSON» внизу формы:

правило: предупредить на 900 ГБ из 1 ТБ
[
  {
    "type": "transfer_out_cycle",
    "max": 966367641600,
    "cycle_start": "2026-08-01T00:00:00+03:00",
    "cycle_interval": 1,
    "cycle_unit": "month",
    "cover": 0
  }
]

Порог считается в байтах, поэтому нужное число гигабайт умножьте на 1073741824. Готовые значения для порога в 90% от пакета:

Пакет хостераПорог 90%Значение max
500 ГБ450 ГБ483183820800
1 ТБ921 ГБ988916219904
2 ТБ1843 ГБ1978906181632

Ниже в форме выберите «Группу уведомлений» (создадим на следующем шаге), а в «Режиме срабатывания» поставьте «Один раз» — тогда придёт одно сообщение при переходе через порог, а не поток одинаковых. Не забудьте галочку «Включить».

Три честные оговорки про счётчик трафика. Первая: Nezha считает трафик с момента установки агента, а не с начала вашего расчётного периода, поэтому в первый месяц её цифра будет меньше хостерской. Вторая: расчётный период у большинства хостеров начинается в день оплаты, а не первого числа — подставьте в cycle_start свою дату. Третья: у хостера и у агента разные точки измерения, расхождение в несколько процентов — норма, поэтому и берём порог 90%, а не 99%.

Вторым правилом заведите оповещение о падении — оно самое простое:

сервер не отвечает ~30 секунд
[
  { "type": "offline", "duration": 10, "cover": 0 }
]

Поле duration здесь — это количество проверок, а не секунд. Панель опрашивает состояние примерно раз в три секунды, так что 10 — это около тридцати секунд подряд без ответа. Минимальное разумное значение — 3; ставить меньше бессмысленно, будете получать ложные срабатывания на каждом сетевом чихе. Значение cover: 0 означает «следить за всеми серверами».

Шаг 6. Уведомления в Telegram

Отдельного «интеграционного» модуля у Nezha нет: любое уведомление — это HTTP-запрос, который панель отправляет по заданному адресу. Для Telegram это делает всё простым.

Сначала бот:

  1. Напишите @BotFather, отправьте /newbot, придумайте имя — получите токен вида 123456789:AAE...
  2. Напишите @userinfobot — он ответит вашим числовым идентификатором
  3. Обязательно напишите что-нибудь своему новому боту — пока вы не начали диалог первым, Telegram не разрешит ему писать вам

Дальше в панели: раздел «Уведомление», вкладка «Уведомитель», кнопка добавления — откроется окно «Создать уведомитель». Название — Telegram, «Метод запроса» — GET, тело запроса оставьте пустым. В поле URL вставьте строку, подставив свой токен и свой идентификатор:

поле URL
https://api.telegram.org/bot123456789:AAE.../sendMessage?chat_id=987654321&text=#NEZHA#

Плейсхолдер #NEZHA# подставляет текст события. Есть и другие — #SERVER.NAME#, #SERVER.IP#, #SERVER.CPU#, #DATETIME# — но для Telegram хватает одного. При сохранении панель сразу отправит тестовое сообщение: если оно пришло, всё настроено верно.

Последний штрих, про который забывают чаще всего: правила тревог отправляют сообщения не напрямую уведомителю, а группе уведомлений. Группы лежат в другом разделе — «Группа», вкладка «Уведомление». Создайте там группу, положите в неё Telegram, и вернитесь в оба правила из прошлого шага, чтобы выбрать её в поле «Группа уведомлений». Без этого шага уведомитель есть, тестовое сообщение приходит, а алерты молчат.

Если сервер панели не ходит в Telegram. Уведомление отправляет сама панель, поэтому доступ к api.telegram.org нужен только с одного сервера — того, где стоит Nezha. Если оттуда не получается, есть три пути: разместить панель у хостера, откуда доступ есть; поднять свой прокси Telegram API и указать его адрес вместо официального; или отправлять уведомления не в Telegram, а на почту или в любой другой сервис с HTTP-адресом. Отдельно учтите: панель по соображениям безопасности отказывается слать уведомления на локальные и внутренние адреса — прокси должен быть доступен по публичному имени.

Публичная страница статуса

Корень домена — https://nezha.example.com/ — это и есть публичная страница: карточки серверов, суммарный трафик, карта и панель проверок сервисов. По умолчанию она открыта всем, без входа. Это удобно, если вы хотите показывать статус пользователям, и совершенно не нужно, если серверы личные.

Что с этим можно сделать — от мягкого к жёсткому:

  • Спрятать отдельный сервер. В «Редактировать сервер» галочка «Скрыто для гостей» — карточка останется видна только вам.
  • Спрятать чувствительное. Гостям и так не видны приватные заметки, а публичные заметки видны всем — не кладите туда ничего лишнего.
  • Закрыть страницу целиком. Добавьте в data/config.yaml строку force_auth: true и перезапустите панель — тогда без входа не покажут ничего.
перезапуск после правки конфига
cd /opt/nezha/dashboard && sudo docker compose restart

Если решили оставить страницу публичной, имеет смысл сделать так, чтобы встроенная защита от подбора паролей видела реальные адреса посетителей, а не адрес Nginx. Для этого добавьте в конфиг ещё одну строку — web_real_ip_header: nz-realip — и перезапустите панель.

Осторожно: этой строкой легко закрыться снаружи. После неё панель перестаёт отвечать на любые запросы, в которых нет заголовка nz-realip — то есть на всё, что идёт мимо Nginx. Мы проверили: прямое обращение к порту 8008 (в том числе через SSH-туннель) начинает возвращать {"error":"real ip header not found"}. Если после перезапуска панель перестала пускать и по домену — значит, в конфиге Nginx потерялась строка proxy_set_header nz-realip $remote_addr;. Аварийный выход: убрать строку web_real_ip_header из data/config.yaml и перезапустить контейнер.

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

Nezha умеет не только смотреть, но и делать. В разделе «Задача» можно завести команду с расписанием в формате cron и запускать её сразу на всех серверах: раз в сутки чистить логи, перезапускать сервис, дёргать бэкап. У каждого сервера есть кнопка с терминалом прямо в браузере и простенький файловый менеджер.

Это действительно удобно. И это же — главный риск всей конструкции, который нужно назвать прямо:

Агент работает от root. Значит, администратор панели Nezha автоматически имеет root на всех подключённых серверах. Взломанная или просто плохо запароленная панель — это не «кто-то увидел мои графики», это «кто-то получил все мои машины». Относитесь к ней как к связке ключей от инфраструктуры.

Отсюда четыре правила, которые стоит выполнить сразу:

  • Длинный уникальный пароль и HTTPS — мы это уже сделали на шагах 2 и 3.
  • Выключите выполнение команд там, где оно не нужно. В конфиге агента параметр disable_command_execute: true запрещает и задачи, и терминал, и файловый менеджер. Ставится он и через панель, кнопкой «Редактировать конфигурацию сервера» — заходить на сервер не нужно.
  • Не селите на сервер панели ничего лишнего. Только Nezha и Nginx.
  • Секрет из команды установки — это пароль. Не выкладывайте его в переписку, issue или чат: кто им владеет, тот может зарегистрировать в вашей панели свой сервер.

Если удалённые команды вам не нужны в принципе, ставьте агенты сразу с этим параметром — допишите в команду установки ещё одну переменную:

агент только для наблюдения, без права выполнять команды
curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.sh -o agent.sh \
  && chmod +x agent.sh \
  && env NZ_SERVER=nezha.example.com:443 \
         NZ_TLS=true \
         NZ_CLIENT_SECRET=ВАШ_СЕКРЕТ \
         NZ_DISABLE_COMMAND_EXECUTE=true \
         ./agent.sh

sudo systemctl enable --now nezha-agent

Получится честный мониторинг без права что-либо менять на серверах. Общие правила про SSH, ключи и файрвол — в нашей статье про безопасность VPS.

Бэкап и обновление

Всё состояние панели лежит в одном каталоге: /opt/nezha/dashboard/data. Там конфиг, база SQLite со списком серверов и правил, и хранилище истории. Чтобы копия была согласованной, панель на время копирования лучше остановить — это несколько секунд:

бэкап
cd /opt/nezha/dashboard
sudo docker compose stop
sudo tar czf ~/nezha-$(date +%F).tar.gz -C /opt/nezha/dashboard data
sudo docker compose start

Полученный архив отправьте туда же, куда возите остальные бэкапы — например, через restic. В конфиге лежит ключ подписи сессий и секреты — архив шифруйте.

Обновление панели — правка одной строки. Посмотрите последнюю версию в разделе Releases репозитория nezhahq/nezha, поменяйте тег в docker-compose.yaml и выполните:

обновление
cd /opt/nezha/dashboard
sudo docker compose pull
sudo docker compose up -d

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

Частые проблемы

Панель открывается, а сервер в ней так и не появился

Сначала убедитесь, что служба вообще запущена: systemctl is-active nezha-agent должно ответить active. Если inactive — установочный скрипт её не стартовал, выполните sudo systemctl enable --now nezha-agent. Если служба работает, смотрим журнал: sudo journalctl -u nezha-agent -n 30 --no-pager. Строка tls: no application protocol означает ровно одно: на Nginx не включён HTTP/2 — вернитесь к шагу 3 и допишите http2 в строку listen 443 ssl. Строка connection refused — агент не достучался до порта 443: проверьте домен в NZ_SERVER и файрвол. Если в журнале вообще пусто, включите в /opt/nezha/agent/config.yml параметр debug: true и перезапустите службу — по умолчанию агент молчит.

В журнале агента «you were blocked by nezha WAF»

Так и есть: у панели встроенная защита от подбора, и после нескольких попыток подключиться с неверным секретом она блокирует адрес. Мы поймали это на проверочной установке — хватило нескольких попыток подряд. Коварство в том, что после исправления секрета агент продолжает получать отказ, пока блокировка не снята. Лечится в «Системные настройки» → «Файрвол (WAF)»: найдите строку с IP своего сервера и удалите её. Агент подключится в течение минуты, перезапускать его не нужно — мы проверили и это.

У всех серверов один и тот же IP-адрес

И этот адрес — адрес самого сервера панели. Значит, панель видит подключение от Nginx, а не от агента. Проверьте две вещи: строку agent_real_ip_header: nz-realip в data/config.yaml и строку grpc_set_header nz-realip $remote_addr; в блоке location ^~ /proto.NezhaService/. Имя заголовка в обоих местах должно совпадать посимвольно. После правки конфига панель нужно перезапустить, Nginx — перезагрузить.

Графики за 7 и 30 дней серые и не нажимаются

Не включено хранилище истории. Проверьте блок tsdb в data/config.yaml и поищите в журнале строку TSDB initialized successfully. Учтите: старая история проверок сервисов при первом включении хранилища не переносится, поэтому включать его лучше сразу, а не через полгода. Ещё одна деталь: гостям доступны только «сейчас» и «1 день», семь и тридцать дней показываются после входа.

Задача из панели падает с «command not found»

Команда выполняется не в вашей привычной оболочке, и переменная PATH там другая. В документации советуют начинать команду с source ~/.bashrc &&, но на Ubuntu это часто не помогает: стандартный ~/.bashrc в самом начале выходит, если оболочка неинтерактивная. Надёжное решение — писать полный путь: /usr/bin/docker вместо docker. Узнать путь: which docker.

Панель отвечает «real ip header not found» и не пускает

Это последствие строки web_real_ip_header в конфиге: панель перестала принимать запросы, в которых нет заголовка с реальным IP. Если так отвечает прямое обращение к порту 8008 — всё в порядке, так и задумано, ходите через домен. Если так отвечает и домен, значит Nginx не проставляет заголовок: проверьте строку proxy_set_header nz-realip $remote_addr; в блоке location /. Аварийный выход — убрать web_real_ip_header из data/config.yaml и выполнить sudo docker compose restart.

Цифры трафика в панели не сходятся с цифрами хостера

Полного совпадения не будет никогда, и это нормально: измеряют в разных точках. Но если расхождение в разы, почти всегда виноваты лишние сетевые интерфейсы — Docker, WireGuard, туннели. Ограничьте учёт внешним интерфейсом через nic_allowlist в конфиге агента. И помните, что счёт начинается с момента установки агента, а не с начала расчётного периода у хостера.

Коротко: порядок действий

  1. Отдельный VPS от 1 ГБ памяти под панель, домен и A-запись на его IP
  2. Docker из get.docker.com, каталог /opt/nezha/dashboard
  3. docker-compose.yaml с портом 127.0.0.1:8008:8008 и data/config.yaml с location, install_host, agent_real_ip_header и блоком tsdb
  4. docker compose up -d, в журнале — TSDB initialized successfully
  5. SSH-туннель ssh -L 8008:127.0.0.1:8008, вход admin/admin, немедленная смена пароля
  6. Nginx с тремя блоками location, certbot --nginx
  7. Дописать http2 в строку listen 443 ssl — иначе агенты не подключатся
  8. Проверить: curl на корень домена показывает HTTP-версия: 2, а на /proto.NezhaService/200 application/grpc
  9. «Команда установки» → Linux → выполнить на каждом сервере, затем sudo systemctl enable --now nezha-agent
  10. Правила: трафик transfer_out_cycle и падение offline
  11. Уведомитель Telegram, группа уведомлений, привязать группу к правилам
  12. Решить судьбу публичной страницы и выключить лишние права агентов

Если не подошло: sudo docker compose down в /opt/nezha/dashboard останавливает панель, каталог data остаётся на месте. Агент удаляется командой sudo /opt/nezha/agent/nezha-agent service -c /opt/nezha/agent/config.yml uninstall, а затем sudo rm -rf /opt/nezha/agent.

Панели Nezha хватает самого простого тарифа — 1 ГБ памяти и 10 ГБ диска

Дешёвые VPS 2026 →