Сквозная миграция HY2XS на современную Hysteria (2.12.2) и переход на v1. Build: - версия Hysteria резолвится на этапе сборки из HyNetworks/hysteria и замораживается в metadata пакета (version + immutable url + sha256); - compatibility gate: реальный бинарник должен принять канонический конфиг HY2XS для gecko и salamander до создания пакета; - сборка прогоняет тесты оркестратора и админки. Конфигурационный контракт: - HY2XS_CONFIG_SCHEMA_VERSION=2, чужая схема отклоняется fail-fast; - obfs стал настоящим union gecko|salamander, gecko — default; - obfs-блок рендерится оркестратором целиком, два подтипа одновременно структурно невозможны; - современный baseline: congestion bbr/standard, disableLossCompensation=false, disableStatelessReset=false, полный quic-блок. Исправления: - share URI для gecko: генератор был завязан на Obfs.Salamander.Password и выдавал нерабочую ссылку при любой другой обфускации; - SNI брался только из ACME-блока и уходил пустым при HY2XS_TLS_MODE=file; - экспорт конфига выносил trafficStats.secret, access_token и obfs-пароль; - экспорт терял неизвестные upstream-поля при round-trip через типизированную модель; - renderRuntimeEnv печатал тип обфускации литералом, расходясь с конфигом; - namedotcom удалён из ACME-реестра (нет в Hysteria с 2.11.0). Тесты: - 95 тестов оркестратора: env, рендер, семантика профиля, резолвер, rollover; - тесты URI и экспорта в Go; - tools/test/e2e-hysteria.sh с реальным клиентом Hysteria. UX: - подсказки и примеры в форме создания пира. Прочее: CHANGELOG.md, .gitattributes (LF для target-side файлов), документация на русском.
9.6 KiB
Build layer and package
Цель документа
Зафиксировать локальный слой сборки и формат итогового install package.
Базовое решение
В baseline builder остаётся shell-first для packaging-слоя.
То есть:
- основной packaging pipeline — sh/bash
- оркестратор при этом пишется на Bun + TypeScript
- builder локально компилирует оркестратор в готовый install-артефакт
- target machine не должна сама собирать или доустанавливать JS/TS toolchain
Причина простая: packaging можно держать простым, а оркестратор — typed и модульным.
Где работает builder
Production builder работает на отдельном build host:
- Debian 13
- amd64 / x86_64
- bash
- доступ к интернету для apt и скачивания toolchain
В текущей production-модели сборка выполняется на Debian 13 amd64, а не на Windows/macOS dev-машине.
Builder не является частью target install flow: на target server приезжает уже готовый install package, без JS/TS/Go build step.
Что хранится в репозитории проекта
Минимум:
- исходники оркестратора на Bun + TypeScript
- shell packaging scripts
- шаблоны конфигов
- systemd unit templates
- docs
- исходный код HY2XS admin
- шаблоны для
post-install.env - package metadata
Что делает builder
- Проверяет структуру проекта.
- Прогоняет тесты и типы оркестратора.
- Разрешает upstream-версию Hysteria и проходит compatibility gate.
- Компилирует оркестратор из Bun/TypeScript в install-артефакт.
- Собирает / подготавливает HY2XS admin.
- Прогоняет тесты HY2XS admin (после сборки frontend:
go:embed all:distтребует готовых ассетов). - Копирует артефакты UI в package staging directory.
- Кладёт entrypoint, templates, docs и service files.
- Формирует итоговый install package.
- Считает manifest/checksum.
- Проверяет архив и прогоняет acceptance-проверки.
- Выдаёт один переносимый результат для target machine.
Что builder не делает
- не ставит Hysteria2 на локальной машине «для продакшена»
- не превращается в CI/CD платформу
- не генерирует update pipeline
- не делает uninstall manifests
- не готовит миграции между старыми инсталляциями
Рекомендуемая структура
project/
├── tools/
│ └── build/
│ ├── build.sh
│ ├── README.md
│ └── lib/
├── orchestrator/
│ ├── package.json
│ ├── bun.lock
│ ├── tsconfig.json
│ └── src/
├── package/
│ ├── install.sh
│ ├── orchestrator/
│ ├── templates/
│ └── systemd/
├── ui/
│ └── hy2xs-admin/
├── docs/
└── dist/
Формат итогового пакета
Итоговый пакет должен содержать:
- install-only orchestrator artifact
- bundled HY2XS admin
- unit templates
- config templates
- docs / examples
- manifest версии проекта
Итоговый пакет не должен содержать:
- builder scripts
- исходную локальную build-среду
- временные каталоги сборки
- мусор CI
- target-side dependency install step для оркестратора
Production builder bootstrap
tools/build/build.sh должен быть самодостаточным для Debian 13 amd64:
- Проверяет ОС и архитектуру.
- Проверяет структуру репозитория и lock-файлы.
- Доставляет отсутствующие системные build-зависимости через
apt-get. - Проверяет версии Go, Bun, Node.js и pnpm.
- При несовпадении версий скачивает управляемый локальный toolchain в
.toolchain/. - Собирает только Linux amd64 артефакты.
- Записывает версии toolchain в metadata пакета.
Отношение к Hysteria2
Сам бинарь Hysteria2 не вендорится в install package как baseline-правило.
Причина:
- ядро Hysteria рассматривается как stable upstream component;
- целевая установка скачивает его с official upstream, но строго по замороженным координатам.
Разрешение версии на сборке
SOURCE
│
▼
resolve latest stable (HyNetworks/hysteria, только теги app/vX.Y.Z)
│
▼
resolve exact release asset (hysteria-linux-amd64)
│
▼
download + compute SHA-256
│
▼
compatibility gate (реальный бинарник принимает канонический конфиг HY2XS)
│
▼
PACKAGE METADATA
version = vX.Y.Z
exact_url = <immutable release asset>
sha256 = <...>
resolution = latest-stable | pinned | override
│
▼
TARGET SERVER
скачивает уже конкретный неизменяемый артефакт
Так одновременно выполняются оба требования: «по умолчанию брать последнюю стабильную» и «production-установка должна быть детерминированной и проверяемой».
Переменные builder:
| Переменная | Значение по умолчанию | Назначение |
|---|---|---|
HYSTERIA_CHANNEL |
stable |
stable — разрешить последнюю стабильную через upstream API; pinned — взять tools/build/hysteria-lock.env без сети |
HYSTERIA_VERSION_OVERRIDE |
пусто | Закрепить конкретную версию vX.Y.Z |
HYSTERIA_COMPAT_GATE |
true |
Compatibility gate; для release-сборок обязателен |
HYSTERIA_WRITE_LOCK |
false |
Записать разрешённые значения обратно в tools/build/hysteria-lock.env |
GITHUB_TOKEN |
пусто | Опционально, чтобы не упереться в anonymous rate limit |
Дополнительно:
- версия, URL и SHA256 фиксируются в metadata install package (
metadata/hysteria.version,metadata/hysteria.url,metadata/hysteria.sha256); - способ выбора версии фиксируется в
metadata/hysteria.resolutionиmetadata/package.env; - runtime
reconfigureне обновляет и не откатывает бинарник Hysteria2; - install flow валидирует SHA256 и фактическую версию установленного бинарника;
- install-time код не обращается к upstream API и не использует moving
latest— это проверяется тестами и acceptance-шагом сборки.
Compatibility gate
Gate защищает от ситуации, когда upstream меняет схему конфигурации, а builder молча собирает неработающий HY2XS.
Порядок:
- скачать артефакт и сверить SHA-256;
- сверить
hysteria versionс разрешённой версией; - отрендерить канонический конфиг HY2XS тем же кодом, что работает на target (
orchestrator/tools/render-canonical-config.ts); - запустить реальный бинарник Hysteria с этим конфигом — для Gecko и для Salamander;
- только после этого собирать release package.
При несовместимости ломается сборка:
BUILD FAILED: unsupported Hysteria stable v2.13.0
Это осознанно: ошибка должна проявиться на build machine, а не на сервере оператора.
Инварианты
Система считается правильной, если:
- builder запускается на Debian 13 amd64 build host, не как target-side build step
- пакет можно перенести на чистый Debian 13
- на сервере нет отдельного build step
- bundled UI уже находится внутри пакета
- оркестратор authored as Bun/TypeScript, но на target приходит как готовый install-артефакт
- Hysteria2 подтягивается install layer'ом с upstream по замороженным координатам, а не собирается на target из исходников
- выход новой версии Hysteria после сборки не меняет содержимое уже собранного пакета
- несовместимый upstream ломает сборку, а не установку у пользователя