Files
HY2XS_flamy/docs/04-admin-panel.md
T
founder 3a4ce9c751 docs: clean-install-only, versions.env и очистка предыдущего поколения
Новый docs/14-legacy-cleanup.md: как выглядит отказ установщика, полный
список маркеров чужой установки, что сохранить перед очисткой, работа
purge-v0.sh, ручная процедура и отдельно - случай незавершённой
установки текущего поколения, где нужен repair, а не очистка.

Обновлено под фактическое поведение:

- README и package/docs: установка описана как две фазы, PHASE 0 ничего
  не меняет; добавлен troubleshooting по отказу clean-host; версии
  toolchain больше не передаются через окружение;
- 02-build-layer: раздел про versions.env (что в нём есть и чего нет и
  почему), verify_versions_contract, проверка происхождения артефакта
  по upstream hashes.txt;
- 08-orchestrator-spec: двухфазный контракт, read-only guard,
  идентификация поколения в install-state, ownership-aware rollback,
  расширенная семантическая проверка конфига, структурная редакция;
- 04-admin-panel: таблица удалённых маршрутов и почему они удалены, а
  не оставлены заглушками; сужена формулировка гарантии санитайза;
- 11-testing: новые unit-наборы, полный список инвариантов конфига,
  раздел про одну реализацию URI вместо двух, сценарий проверки
  границы установки на живом сервере;
- 12-operations и 13-runbook: диагностика отказов по поколению,
  поведение diagnostics-бандла;
- tools/build/README: контракт версий, обе суммы Bun, hashes.txt.

CHANGELOG: раздел Unreleased с разбором каждого исправленного дефекта.
2026-08-27 12:16:38 +05:00

13 KiB
Raw Blame History

Admin panel: HY2XS admin

Цель документа

Зафиксировать модель работы с admin-панелью: HY2XS admin является штатным компонентом HY2XS, а не внешней зависимостью, которую target server где-то добывает во время установки.

Место компонента в системе

Проект состоит из компонентов двух разных типов:

  • Hysteria2 — external runtime dependency. Ванильный upstream-бинарник, который оркестратор забирает из официального источника во время установки.
  • HY2XS admin — native HY2XS component. Исходный код лежит в репозитории, компонент собирается production builder'ом вместе с остальными артефактами HY2XS.

Это противопоставление и есть основная архитектурная граница.

Состав компонента

  • исходный код admin-компонента хранится в apps/;
  • backend реализован на Go;
  • frontend реализован на Vue/Vite;
  • frontend-ассеты встраиваются в Go-бинарник;
  • компонент собирается production builder'ом вместе с остальными артефактами HY2XS;
  • готовый бинарник едет в install package как ui/hy2xs-admin/hy2xs-admin.

Правила поставки

HY2XS admin:

  • поставляется внутри итогового пакета;
  • имеет свой install dir;
  • имеет свой data dir;
  • запускается отдельным rootless systemd unit (hy2xs-admin);
  • не требует target-side build.

Target server не собирает admin-компонент из исходного кода и не скачивает его из внешнего репозитория.

Scope панели

Панель нужна для:

  • operator-facing управления;
  • просмотра статуса;
  • работы с пользователями / трафиком / сущностями доступа;
  • удобной админской рутины.

Панель не должна:

  • определять install lifecycle сервера;
  • превращать систему в сложный control plane;
  • диктовать scope оркестратора.

HY2XS admin работает как надстройка над Hysteria YAML/API-слоем. Это нормально: важно только, чтобы источник истины по runtime-состоянию был понятен и не было двух конкурирующих конфигурационных миров без правил синхронизации.

Относительно конфигурации Hysteria панель read-only: конфиг генерирует оркестратор.

Два слоя работы с конфигом Hysteria

Это важное архитектурное разделение.

Слой Назначение Поведение при неизвестных полях
Типизированная модель отображение известных HY2XS полей в UI неизвестные поля не отображаются
Сырой YAML экспорт и сохранение неизвестные поля сохраняются

Причина: если бы экспорт работал через типизированную модель (Unmarshal → структура → Marshal), то любое поле, о котором HY2XS ещё не знает, терялось бы при round-trip. Панель незаметно урезала бы современный конфиг.

Поэтому:

  • экспорт читает исходный YAML и сохраняет структуру документа целиком;
  • будущие версии Hysteria не ломают экспорт только потому, что backend и frontend ещё не научились показывать новый параметр;
  • это прямое следствие модели «latest stable на сборке»: схема upstream может опережать модель HY2XS.

Санитайз экспорта

Экспортируемый файл покидает сервер, поэтому секреты из него вырезаются:

  • пароли обфускации (obfs.*.password);
  • trafficStats.secret;
  • access_token в auth-URL и учётные данные, встроенные в URL;
  • auth.password, auth.userpass;
  • учётные данные ACME DNS-провайдера;
  • неизвестные поля с секретоподобным именем: password, passwd, passphrase, secret, token, credential, apiKey / api_key, privateKey / private_key, accessKey, secretKey, authorization, cookie, bearer, signature.

Последний пункт — обратная сторона сохранения неизвестных полей: новое upstream-поле с секретом вырезается ещё до того, как HY2XS про него узнает.

Как формулируется гарантия

Точная формулировка:

вырезаются известные секреты и неизвестные поля с секретоподобным именем.

Не «любой будущий секрет будет автоматически удалён». Обобщённый sanitizer работает по именам полей и не может предугадать произвольное имя, которое upstream выберет для нового секрета. Список маркеров синхронизирован с orchestrator/src/lib/redaction.ts; при появлении нового поля его нужно добавить в оба места.

Пути к файлам (tls.cert, tls.key, ech.keyPath, tls.clientCA) секретами не считаются и остаются читаемыми — они нужны для диагностики.

Модель современной схемы Hysteria

Модель админки понимает актуальную серверную схему, даже там, где UI не позволяет ничего включить: obfs.gecko, ech, congestion, mimic, realm, tls.clientCA, quic.disableStatelessReset, bandwidth.disableLossCompensation, masquerade.proxy.xForwarded.

Смысл в том, чтобы admin понимал текущую upstream-схему, а не считал неизвестными поля собственного конфига.

Генерация клиентских ссылок

  • тип обфускации и пароль берутся из фактического конфига одинаково для всех поддерживаемых типов (gecko, salamander);
  • неизвестный тип обфускации в ссылку не попадает: лучше отсутствие параметра, чем параметр, который клиент не понимает;
  • публичный endpoint берётся из HY2XS_PUBLIC_HOST + HY2XS_PUBLIC_PORT, а не из listen или Host-заголовка запроса;
  • SNI берётся из ACME-домена, затем из HY2XS_DOMAIN, затем из HY2XS_PUBLIC_HOST; IP-адрес как SNI не используется;
  • minPacketSize/maxPacketSize Gecko в ссылку не помещаются — поэтому HY2XS держит их на upstream-defaults 512/1200.

Правила ответственности

Source of truth

  • runtime transport layer: Hysteria2
  • операторский UI layer: HY2XS admin
  • install lifecycle: оркестратор HY2XS
  • deploy facts: post-install.env

Production lifecycle Hysteria2

В production package HY2XS admin не скачивает и не обновляет бинарь Hysteria2 самостоятельно.

Правильная модель:

  • Hysteria2 устанавливается install-оркестратором с official upstream;
  • Hysteria2 запускается отдельным hysteria-server.service;
  • HY2XS admin работает как operator UI и HTTP auth/traffic layer;
  • HY2XS admin не запускается от root;
  • смена версии Hysteria2 через UI отсутствует как API;
  • список upstream releases не является частью operator UI baseline;
  • port hopping не является частью production path.

Удалённые операции: почему не заглушки

Маршруты, которые продукт принципиально не поддерживает, удалены, а не оставлены отвечающими «feature disabled»:

Удалённый маршрут Кто владеет операцией
POST /hysteria2ChangeVersion install-оркестратор
GET /listRelease build layer
POST /config/updateHysteria2Config install-оркестратор
POST /config/importHysteria2Config install-оркестратор
POST /config/restartServer systemd
POST /config/uploadCertFile оператор + оркестратор
GET /config/hysteria2AcmePath не имел потребителя

Причины две.

Во-первых, API-контракт не должен даже обещать updater, которого у продукта нет: маршрут, всегда возвращающий отказ, вводит в заблуждение.

Во-вторых, это лишняя attack surface и технический мусор от прежней архитектуры.

Вместе с маршрутами удалены соответствующие клиентские функции фронтенда, кнопки и строки i18n. Кнопка, которая гарантированно возвращает ошибку, — не «точка расширения на будущее», а дефект UX. Возвращение любого из этих маршрутов ломает acceptance-проверку сборки.

Конфигурация Hysteria остаётся доступной панели на чтение и на выгрузку: GET /config/getHysteria2Config и POST /config/exportHysteria2Config.

Что нельзя делать

  • собирать admin-компонент на target server;
  • скачивать admin-компонент на target из внешнего репозитория;
  • склеивать unit Hysteria2 и unit HY2XS admin в один сервис;
  • раздувать оркестратор из-за особенностей панели;
  • использовать HY2XS admin как updater бинаря Hysteria2;
  • использовать JWT_SECRET как trafficStats.secret для Hysteria API;
  • экспортировать конфиг Hysteria через типизированную модель — так теряются неизвестные upstream-поля;
  • выгружать конфиг с секретами в открытом виде.

Что фиксировать в post-install.env

Минимум:

  • HY2XS_ADMIN_ENABLED
  • HY2XS_ADMIN_SOURCE
  • HY2XS_ADMIN_BUILD_ID
  • HY2XS_ADMIN_BIND_HOST
  • HY2XS_ADMIN_PORT
  • HY2XS_ADMIN_INSTALL_DIR
  • HY2XS_ADMIN_DATA_DIR
  • HY2XS_ADMIN_LOG_DIR

Инварианты

Схема считается корректной, если:

  1. HY2XS admin приезжает на target уже в составе пакета
  2. target не скачивает и не собирает admin-компонент
  3. HY2XS admin работает отдельным сервисом
  4. HY2XS admin не меняет install-only scope оркестратора
  5. Hysteria2 остаётся внешним vanilla upstream-компонентом
  6. HY2XS admin не выступает updater-менеджером Hysteria2
  7. trafficStats.secret не связан с JWT_SECRET
  8. экспорт конфига сохраняет неизвестные upstream-поля
  9. экспорт конфига не содержит секретов
  10. сгенерированная hysteria2:// ссылка содержит фактический тип обфускации, и совместимый клиент подключается по ней напрямую