📡 Внешние диагностические проберы

August 9, 2026 · View on GitHub

Read this in English.

Пробер — небольшой Go-бинарник, который вы ставите на свой сервер. Он получает от панели скрытую подписку, поднимает то же ядро, что и клиенты Click Connect, подключается к вашим нодам так же, как это делает клиент, и присылает результат.


📖 Зачем это нужно

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

  • порт режется конкретным оператором;
  • маскировочный destination REALITY мёртв, и TLS-хендшейк не завершается;
  • пользователь не доехал до запущенного Xray, и креды отвергаются;
  • туннель поднят, но данные не идут из-за сломанного outbound или правила ACL;
  • IP выхода попал в чёрный список, и конкретный ресурс блокируется.

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


🧭 Как это работает

┌──────────────────────┐                              ┌──────────────────────┐
│       ПРОБЕР         │    1. enroll (разовый)       │        ПАНЕЛЬ        │
│     ваш сервер       │ ───────────────────────────▶ │                      │
│                      │                              │                      │
│  ┌────────────────┐  │    2. профиль + подписка     │                      │
│  │    sing-box    │  │ ◀─────────────────────────── │                      │
│  └───────┬────────┘  │                              │                      │
│          │           │    4. gzip NDJSON            │                      │
│          │           │ ───────────────────────────▶ │                      │
└──────────┼───────────┘                              └──────────────────────┘

           │  3. реальные подключения — свой SOCKS-порт на каждый инбаунд

┌────────────────────────────────────────────────────────────────────────────┐
│   нода A        нода B        нода C     виртуальная нода (группа urltest) │
└────────────────────────────────────────────────────────────────────────────┘
  1. Регистрация. Панель выдаёт одноразовый токен, действующий 24 часа. Пробер один раз меняет его на постоянный; для проверки хранятся только SHA-256-хеши.
  2. Профиль. Пробер спрашивает, что проверять: ноды, инбаунды, чек-лист ресурсов, периодичность и бюджет замера скорости.
  3. Подписка. У каждого пробера есть скрытый пользователь со своей подпиской. Он исключён из всех списков и статистики, поэтому трафик пробера никогда не смешивается с клиентским.
  4. Проверки. На каждый проверяемый инбаунд поднимается отдельный локальный SOCKS-листенер, поэтому каждое измерение привязано к конкретному инбаунду конкретной ноды.
  5. Отчёты. Результаты агрегируются локально в окна и отправляются в gzip. Недоставленные батчи складываются в спул на диске, поэтому недоступность панели не стоит вам ни одного измерения.

Панель никогда не подключается к проберу: всё инициирует он сам, поэтому пробер работает за NAT и на домашних каналах.


🚀 Установка

Сначала включите фичу: Настройки → Проберы → Включить внешние проберы. Пока она выключена, панель отклоняет и регистрацию, и отчёты.

Дальше Проберы → Добавить пробер. Имя стоит давать по точке наблюдения (Москва, МТС полезно, probe-1 — нет), после чего выполните сгенерированную команду на том хосте, откуда хотите проверять.

Linux / macOS:

curl -fsSL https://github.com/ClickDevTech/CELERITY-panel/releases/latest/download/celerity-probe-install.sh \
  | sudo PANEL_URL='https://panel.example.com' ENROLL_TOKEN='<токен>' sh

Windows (PowerShell от администратора):

$env:PANEL_URL='https://panel.example.com'; $env:ENROLL_TOKEN='<токен>'
irm https://github.com/ClickDevTech/CELERITY-panel/releases/latest/download/celerity-probe-install.ps1 | iex

Установщик скачивает пробер и ядро, один раз проходит регистрацию и ставит службу (systemd, launchd или служба Windows). Токен регистрации передаётся через окружение, потому что таблица процессов доступна другим локальным пользователям.

Ядро — sing-box-lx, та же сборка, что стоит в приложениях Click Connect: апстрим sing-box плюс транспорты, которые умеет публиковать панель. Апстримное ядро отвергает целиком конфигурацию, где есть нода на XHTTP, — пробер на нём ослеп бы разом по всем нодам. Установка поверх апстримного ядра заменяет его, а если у запущенного ядра нет with_xhttp, при наличии XHTTP-нод пробер пишет об этом в лог. Переменная CORE_REPO позволяет взять ядро из другого репозитория.

ПлатформаСлужбаКаталог данных
Linuxsystemd, работает от аккаунта celerity-probe/var/lib/celerity-probe
macOSlaunchd/usr/local/var/celerity-probe
Windowsслужба Windows, ACL каталога ограничен SYSTEM и администраторами%ProgramData%\celerity-probe

PANEL_URL обязан быть HTTPS. Токен пробера аутентифицирует каждый запрос, а отчёты описывают весь ваш парк нод, поэтому обычный HTTP отклоняется — исключения только для панели на loopback или при PROBE_ALLOW_INSECURE=1 для лабораторного стенда.


⚙️ Настройки

НастройкаПо умолчаниюЧто задаёт
Интервал проверки подключения300 сКак часто прозванивается каждый инбаунд каждой ноды
Интервал проверки ресурсов3600 сКак часто чек-лист запрашивается через каждую ноду
Интервал отчётов900 сКак часто окна уезжают в панель
Хранение30 днейДля сырых окон; часовые роллапы живут втрое дольше
Лимит трафика пробера5 ГБОграничение скрытого пользователя, применяется и к уже созданным проберам
Замер скоростивыключенКаждая нода раз в 180 мин, 20 МБ и 5 с на прогон, 1 ГБ в сутки
Чек-лист ресурсовпустоПара id + url в строке, проверяется через каждую ноду

У скорости своя периодичность: вы задаёте, как часто замеряется одна нода, пробер размазывает этот период по своим инбаундам, а дневной бюджет остаётся предохранителем. Объём замера задаёт и потолок измерения — первая четверть прогона, но не больше 512 КБ, отбрасывается как разгон, а прогон, выбравший объём раньше таймаута, показывается как нижняя граница ≥ X Мбит/с; страница настроек считает этот потолок и суточный расход прямо по ходу ввода.

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


🔍 Как читать результаты

Результаты всегда показываются по точкам наблюдения, и вердикт пробера не меняет node.status. Неуспешная проверка может быть вызвана и аплинком самого пробера; чтобы различать эти случаи, нужен кворум проберов в разных сетях.

Проберы → История открывает отчёт по одной точке наблюдения за 6 часов, 24 часа, 7 или 30 дней. Сверху — числа по всему периоду: доля успешных проверок, задержка p50/p95, хендшейк и время до первого байта, скорость, сколько нод с проблемами, сколько ресурсов из чек-листа заблокировано и сколько времени пробер вообще ничего не присылал. Следом — разбивка отказов по кодам: именно она превращает красную полоску в конкретное действие.

Ниже — по секции на ноду, худшие сверху, здоровые свёрнуты. Каждый инбаунд получает полоску на фиксированной сетке времени: один сегмент — одно окно, цвет — вердикт, под полоской на той же сетке нарисована задержка. Сетка фиксированная, поэтому промежуток, когда пробер молчал, остаётся видимой дырой, а не схлопывается. Клик по сегменту раскрывает окно целиком: попытки и успехи, счётчики отказов, p50/p95, хендшейк, время до первого байта, скорость, адрес выхода, а для виртуальной ноды — какой лист реально выбрал балансировщик.

Периоды длиннее 12 часов читаются из часовых сводок, поэтому месяц обходится так же дёшево, как сутки. Если парк настолько велик, что данные не помещаются в одно чтение, теряется дальний конец периода, а не свежие окна, и панель об этом предупреждает.

Коды отказов указывают на конкретную причину:

КодЧто значитКуда смотреть
net_unreachableTCP/UDP не доходитПорт режется оператором, фаервол или нода лежит
handshake_failedTLS/REALITY не завершаетсяМёртвый маскировочный destination, неверный SNI, вмешательство DPI
auth_rejectedТуннель есть, креды отвергнутыПользователь не доехал до запущенного ядра — проблема синхронизации
tunnel_no_dataАвторизация прошла, но данные не идутСломанный outbound или правило ACL
degradedРаботает, но медленноПерегрузка или плохой маршрут именно до этой точки
core_downНе работал собственный sing-box пробераПроблема на хосте пробера

Результаты по ресурсам вынесены отдельно: заблокированный ресурс указывает на гео-блок или адрес выхода в чёрном списке. Блокировкой считаются только 403 и 451; 500 или транспортная ошибка записывается как неуспешная проверка. У каждого ресурса своя полоска, URL, по которому он проверялся, последний HTTP-статус и текст последней ошибки.

Замеры скорости вынесены в отдельный блок, потому что они идут по кругу в рамках дневного бюджета и потому редки и неравномерны. Вместо полоски, которая была бы почти пустой, показаны только те ноды, где замеры реально были — медленные сверху: медиана по настоящим замерам, пик, их количество и время последнего, а сами точки стоят там, где замер произошёл. Окна без замера в медиану не входят и не считаются нулями, часовая сводка хранит медиану часа, а не его лучшую минуту, иначе затяжная просадка спряталась бы за одним удачным всплеском, а перед числом означает, что замер выбрал объём раньше таймаута.

Два предупреждения, на которые стоит реагировать:

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

🪝 Оповещения

Вебхуки срабатывают на переходах состояния, поэтому оповещение приходит, не дожидаясь роллапа:

СобытиеКогда срабатывает
probe.node_unreachableИнбаунд ноды перешёл в состояние отказа из этой точки
probe.target_unreachableРесурс из чек-листа стал недоступен через ноду
probe.offlineПробер пропустил три интервала отчёта

Локальный отказ ядра (core_down) никогда не поднимает алерт по ноде.


🤖 AI-ассистент

MCP-инструмент query_probes отдаёт те же данные AI-клиенту. Ему нужен отдельный скоуп probes:read, потому что данные проберов раскрывают точки наблюдения и адреса выхода. Подробности — в руководстве по MCP.


🔐 Модель безопасности

  • У пробера есть только клиентские креды. Никаких прав на нодах, никакого SSH, никакой сессии панели.
  • Токены проверяются по SHA-256-хешам и сравниваются за постоянное время. Постоянный токен дополнительно хранится в зашифрованном виде, чтобы панель могла повторно показать команду установки.
  • Удаление пробера немедленно убирает его скрытого пользователя, подписку и результаты и проталкивает удаление в запущенные Xray. Привязки к IP или ASN нет, поэтому срок жизни утёкших кредов ограничен скоростью отзыва.
  • Второе ограничение — лимит трафика скрытого пользователя: утёкшая подписка пробера ограничена этим объёмом.
  • Приём данных идемпотентен. Повторно доставленный батч подтверждается без повторной записи, что делает безопасной доставку «хотя бы один раз».

🧯 Диагностика проблем

СимптомВероятная причина
Пробер остался в статусе «ожидает установки»Токен регистрации истёк (24 ч) или уже использован — перевыпустите его в панели
По всем нодам core_downНа хосте пробера нет sing-box или он не исполняемый; смотрите лог службы
По всем нодам auth_rejectedПользователь пробера не доехал до нод — запустите синхронизацию и проверьте статус нод
На одной ноде net_unreachable, на остальных всё в порядкеПорт режется на пути из этой точки наблюдения
После установки нет данныхФича выключена в настройках либо пробер не достучался до PANEL_URL по HTTPS

Логи: sudo journalctl -u celerity-probe -f (Linux — без root журнал ничего не покажет), tail -f /usr/local/var/celerity-probe/probe.log (macOS), лог службы в каталоге данных (Windows).


📚 Исходники

ФайлОписание
probe/Сам пробер (отдельный Go-модуль)
src/routes/probe.jsЭндпоинты регистрации, профиля и приёма данных
src/services/probes/Сервисы регистрации, манифеста, приёма и роллапа
src/routes/panel/probes.jsАдминский интерфейс и JSON API
src/mcp/tools/probes.jsMCP-инструмент query_probes