Мониторинг и метрики
Панель сама следит за каждым узлом и сохраняет увиденное. Эта страница объясняет, что она записывает, как полоса доступности решает, что рисовать, как читаются живые соединения и что экспортирует эндпоинт метрик. Каждое правило здесь следует одной идее: панель показывает то, что знает, и прямо говорит, когда не знает, вместо того чтобы рисовать ноль или сбой, который не может доказать.
Что heartbeat сообщает панели
Каждые 15 секунд каждый узел сообщает, запускает ли он то, что получил, число открытых соединений всего и по инбаундам, сколько раз перезапускалось его ядро и последнюю ошибку запуска, а также счёт соединений, которые отклонили его блокирующие аутбаунды. Панель держит это в памяти, пока узел продолжает отвечать. Узел, который перестал отвечать, показывает «нет данных», а не свои последние цифры.
История состояния
Каждые 5 минут панель запрашивает у каждого подключённого узла показатели хоста: диск, память и нагрузку. Каждый замер сразу показывается на узле и сохраняется в истории состояния.
- За последние 7 дней хранится каждый 5-минутный замер.
- Более старые замеры сворачиваются в один на узел за час — среднее по замерам, в которых был каждый показатель.
- История хранится 90 дней по умолчанию, до двух лет. 0 останавливает запись и очищает её.
- Замер, в котором узел ничего не сообщил, никогда не сохраняется. У узла, который не может сообщать показатели хоста, нет истории, а не история из нулей.
Полоса доступности
Полоса на узле делит окно времени на три состояния:
| Состояние | Как показано | Что значит |
|---|---|---|
| Работает | В сети | у панели есть замер от узла за этот интервал |
| Не работает | Не отвечал | панель работала весь интервал, а узел не дал ни одного замера |
| Неизвестно | Не наблюдался | панель не может сказать: она была выключена, узла ещё не было или узел никогда не давал замеров |
Полоса никогда не рисует сбой, который не может доказать. Интервал считается нерабочим, только если один запуск панели наблюдал его целиком и ничего не услышал. Интервал рядом с перезапуском панели считается неизвестным, а не нерабочим. Узел, который вообще никогда не сообщал показатели хоста, потому что работает на платформе, где это невозможно, может отлично обслуживать, поэтому его полоса остаётся неизвестной, а не красной.
Чтобы отличить «панель была выключена» от «узел не работал», панель записывает каждый свой запуск: когда он начался, когда она последний раз была жива и остановилась ли она штатно. Полоса использует 5-минутные интервалы в пределах последних 7 дней и часовые дальше, в соответствии с хранимой историей.
Живые соединения по запросу
С узлов на панель ничего не передаётся потоком. Узел держит список живых соединений в памяти, а панель спрашивает, когда вы смотрите:
- Счётчики для пользователя приходят со всех подключённых узлов сразу, из итогов, которые каждый узел поддерживает в актуальном состоянии, поэтому запрос дешёвый.
- Строки (источник, назначение, правило, аутбаунд, сеть, возраст, байты) приходят с одного узла за раз, обновляются каждые 10 секунд, пока открыт диалог, новые сверху, не больше 500 строк. Счётчики остаются полными, даже когда строки обрезаны.
- Назначение — это живое состояние, а не запись. Панель не записывает, куда подключаются пользователи.
Закрытие соединений пользователя работает по инбаунду, по аутбаунду, по узлу или везде. Это не блокировка: приложение переподключается при следующем пакете, если пользователь не отключён.
Эндпоинт метрик
Панель публикует свои показатели по адресу /metrics в формате Prometheus, для ваших собственных Prometheus и Grafana. Их настройка, готовый дашборд Grafana и имена всех метрик описаны ниже.
- Нужен токен. Используйте API-токен только с областью
stats:read. Документ называет каждый узел и его адрес, поэтому открытого режима нет. - Всё — по узлу, по фиксированной категории или по всему парку. Ничего не размечено по пользователям: одна метка на учётную запись — это один ряд на учётную запись, хранимый весь срок хранения. Вопросы об одной учётной записи решает API отчётов панели (
/api/reports/*) за выбранный вами период. - Отсутствует, а не ноль. У показателя, который узел не сообщил (диск, память, нагрузка, соединения, перезапуски, пользователи онлайн), ряда нет вовсе. Разрыв на графике значит, что панель не знает, а не что число упало.
- Единственное исключение — число доставок событий по состоянию, которое экспортируется всегда, чтобы могло сработать оповещение о мёртвых доставках.
- Отклонённые соединения экспортируются по узлу и по блокирующему аутбаунду.
Каждый опрос вычисляется из базы данных и живых показателей в этот момент, поэтому при интервале опроса 60 секунд ничего не теряется.
Prometheus и Grafana
Репозиторий панели содержит конфигурацию опроса Prometheus, дашборд Grafana и дополнительный compose-файл, который запускает оба рядом с панелью в Docker.
С Docker
Дополнительный файл подключается к compose-сети панели и обращается к панели по имени сервиса; панели не нужен дополнительный опубликованный порт.
# 1. Fetch the monitoring directory next to your docker-compose.yml
curl -fsSL https://github.com/nexora-vpn/panel/archive/refs/heads/main.tar.gz \
| tar -xz --strip-components=1 panel-main/monitoring
# 2. Put a token with the stats:read scope where Prometheus reads it
printf '%s' 'PASTE-THE-TOKEN' > monitoring/prometheus/token
# 3. Set Grafana's password
cp monitoring/.env.example .env # or merge its lines into your .env
nano .env
# 4. Start everything
docker compose -f docker-compose.yml -f monitoring/docker-compose.monitoring.yml up -dС этого момента всегда указывайте оба файла -f, иначе обычный docker compose up -d снова удалит два сервиса. Чтобы это происходило автоматически:
echo 'COMPOSE_FILE=docker-compose.yml:monitoring/docker-compose.monitoring.yml' >> .envGrafana слушает только loopback сервера. Подключайтесь к ней через SSH:
ssh -L 3000:localhost:3000 you@your-server
# then open http://localhost:3000 and sign in with GRAFANA_PASSWORDДашборд Nexora fleet уже там. Prometheus не публикуется вовсе: у него нет собственного входа, а хранит он всю вашу эксплуатационную картину.
- Панель сама обслуживает HTTPS: в
monitoring/prometheus/prometheus.ymlзадайтеscheme: httpsиtls_config: { insecure_skip_verify: true }. Сертификат панели называет ваше публичное имя хоста, а не имя сервисаpanel, к которому подключается Prometheus. - У панели есть базовый путь: задайте
metrics_path: /your-base-path/metrics. - У панели задано имя хоста:
/metricsотвечает только на этом имени. Дайте сервису панели это имя как сетевой псевдоним в своём compose-файле (networks: { default: { aliases: [panel.example.com] } }) и опрашивайтеpanel.example.com:2095.
Без Docker
scrape_configs:
- job_name: nexora-panel
scheme: https
metrics_path: /metrics
authorization:
type: Bearer
credentials_file: /etc/prometheus/nexora-token
static_configs:
- targets: ['panel.example.com']Для Grafana импортируйте monitoring/grafana/dashboards/nexora-fleet.json из репозитория панели. Он ожидает источник данных Prometheus с uid nexora-prometheus.
Токен
Создайте его на странице токенов API с областью stats:read и ничем больше и храните в отдельном файле, а не внутри prometheus.yml, который часто вставляют в чаты. Отзыв токена сразу останавливает опрос.
Что экспортируется
| Метрика | Значение |
|---|---|
nexora_panel_build_info | 1, с работающей версией в метке |
nexora_panel_start_time_seconds | когда запустился процесс панели; time() - this — время работы |
nexora_license_valid | 1, пока лицензия действительна, иначе 0 |
nexora_license_expires_at_seconds | срок действия лицензии; отсутствует, если лицензия бессрочная |
nexora_license_limit{resource}, nexora_license_used{resource} | предел и текущее число для user и node (−1 = без ограничений) |
nexora_users_total{status} | учётные записи по состоянию: active, disabled, expired, limited, pending |
nexora_users_online | учётные записи с трафиком в окне онлайна |
nexora_nodes_total | узлы, известные панели |
nexora_node_up, nexora_node_enabled | по узлу: отвечает и включён |
nexora_node_traffic_bytes_total{direction} | трафик, учтённый на узле |
nexora_node_online_users | учётные записи с трафиком на этом узле в окне онлайна |
nexora_node_connections, nexora_node_engine_restarts_total | открытые соединения; перезапуски с момента запуска узла |
nexora_node_rejected_connections_total{outbound} | соединения, отклонённые блокирующим аутбаундом |
nexora_node_disk_bytes, nexora_node_disk_used_bytes, nexora_node_memory_bytes, nexora_node_memory_used_bytes, nexora_node_load1 | хост узла |
nexora_event_deliveries{status}, nexora_event_subscribers | доставки событий по состоянию (pending, delivered, dead) и включённые подписчики |
Каждая метрика узла несёт метки node (его имя) и id.
Полезные оповещения
groups:
- name: nexora
rules:
- alert: NexoraPanelDown
expr: up{job="nexora-panel"} == 0
for: 5m
- alert: NexoraNodeDown # a switched-off node is not an outage
expr: nexora_node_up == 0 and nexora_node_enabled == 1
for: 10m
- alert: NexoraNodeDiskFilling
expr: nexora_node_disk_used_bytes / nexora_node_disk_bytes > 0.9
for: 30m
- alert: NexoraEventDeliveriesDead
expr: increase(nexora_event_deliveries{status="dead"}[1h]) > 0Если вы продаёте по лицензии, добавьте nexora_license_expires_at_seconds - time() < 7 * 86400.
Оповещения как события
Несколько вещей панель оценивает сама и создаёт событие, когда они меняются, один раз при пересечении порога и ещё раз при восстановлении:
| Событие | Когда |
|---|---|
node.disconnected, node.connected | узел перестаёт или начинает отвечать |
node.disk_high, node.disk_recovered | заполнение диска пересекает порог, по умолчанию 90%; восстановление — на пять пунктов ниже |
node.memory_high, node.memory_recovered | то же для памяти |
node.rejections_high | отказы через один блокирующий аутбаунд превышают частоту в час, по умолчанию 100 |
node.limit_reached | периодический лимит трафика узла отключил его |
Пороги задаются на странице Вебхуки; 0 отключает оповещение. Частота отказов измеряется за скользящий час по тому, что наблюдала сама панель, поэтому большой счёт, присланный в первом heartbeat после перезапуска панели, — это история, а не всплеск. События доходят до вебхуков, Telegram, почты и дополнений; см. Шина событий.
Связанные страницы
- Дашборд: весь парк узлов одним взглядом.
- Узлы: график состояния узла и полоса доступности.
- Трафик, квоты и лимиты: как вычисляются трафик и счётчики онлайна.
