ddf0ddf71e
Сквозная миграция 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 файлов), документация на русском.
307 lines
13 KiB
Markdown
307 lines
13 KiB
Markdown
# HY2XS production builder
|
||
|
||
Этот каталог содержит production builder для HY2XS.
|
||
|
||
Builder собирает один переносимый install-archive:
|
||
|
||
```text
|
||
dist/hy2xs-install-<version>.tar.gz
|
||
```
|
||
|
||
Этот архив переносится на production server, распаковывается и устанавливается через [`install.sh`](../../package/install.sh).
|
||
|
||
На production server не должно быть сборки из исходников: без `go build`, без `bun install`, без `pnpm install`, без frontend build и без TypeScript transpilation.
|
||
|
||
## Что где лежит
|
||
|
||
Основные части проекта:
|
||
|
||
- [`tools/build/build.sh`](build.sh) — главный entrypoint сборки.
|
||
- [`tools/build/lib/deps.sh`](lib/deps.sh) — проверка Debian/amd64, установка build dependencies, установка Go/Bun/Node.js/pnpm.
|
||
- [`tools/build/lib/package.sh`](lib/package.sh) — сборка orchestrator, сборка HY2XS admin, создание stage directory и tar.gz архива.
|
||
- [`tools/build/lib/verify.sh`](lib/verify.sh) — проверка структуры репозитория и итогового архива.
|
||
- [`tools/build/lib/acceptance.sh`](lib/acceptance.sh) — acceptance-проверки production-контракта.
|
||
- [`tools/build/lib/hysteria.sh`](lib/hysteria.sh) — разрешение upstream-версии Hysteria и compatibility gate.
|
||
- [`tools/build/hysteria-lock.env`](hysteria-lock.env) — fallback-значения для офлайн-сборки (`HYSTERIA_CHANNEL=pinned`).
|
||
- [`tools/test/e2e-hysteria.sh`](../test/e2e-hysteria.sh) — end-to-end проверка с реальным клиентом Hysteria.
|
||
- [`orchestrator`](../../orchestrator) — TypeScript/Bun install-only orchestrator.
|
||
- [`apps`](../../apps) — HY2XS admin: Go backend и Vue frontend.
|
||
- [`package`](../../package) — skeleton будущего install package: `install.sh`, templates, systemd units, default config.
|
||
- [`dist`](../../dist) — итоговые архивы. Создаётся builder'ом, в git обычно не хранится.
|
||
- [`.toolchain`](../../.toolchain) — локальный toolchain builder'а. Создаётся автоматически, в git не хранится.
|
||
|
||
## Требования к build machine
|
||
|
||
Production build поддерживается только на:
|
||
|
||
- Debian 13;
|
||
- amd64 / x86_64;
|
||
- root или пользователь с `sudo`;
|
||
- доступ в интернет.
|
||
|
||
Нужен outbound HTTPS/DNS до:
|
||
|
||
- Debian apt repositories;
|
||
- `go.dev`;
|
||
- `github.com`;
|
||
- `nodejs.org`;
|
||
- npm registry.
|
||
|
||
Windows и macOS можно использовать для редактирования исходников, но финальную production-сборку надо делать на Debian 13 amd64.
|
||
|
||
## Что builder делает сам
|
||
|
||
При запуске builder:
|
||
|
||
1. Проверяет, что host — Debian 13 amd64.
|
||
2. Проверяет структуру репозитория.
|
||
3. Устанавливает недостающие системные build dependencies через `apt-get`.
|
||
4. Проверяет или скачивает локальные версии:
|
||
- Go `1.21.13`;
|
||
- Bun `1.3.13`;
|
||
- Node.js `20.19.0`;
|
||
- pnpm `9.15.9`.
|
||
5. Прогоняет тесты и типы оркестратора (`bun test`, `tsc --noEmit`).
|
||
6. Разрешает upstream-версию Hysteria, скачивает артефакт и считает SHA-256.
|
||
7. Проходит compatibility gate: реальный бинарник Hysteria должен принять канонический конфиг HY2XS.
|
||
8. Копирует package skeleton.
|
||
9. Собирает install-only orchestrator в standalone binary.
|
||
10. Собирает frontend и backend HY2XS admin в Linux amd64 binary.
|
||
11. Прогоняет `go vet` и `go test` для HY2XS admin (после сборки frontend, потому что `go:embed all:dist` требует готовых ассетов).
|
||
12. Записывает metadata и checksums.
|
||
13. Создаёт `dist/hy2xs-install-<version>.tar.gz`.
|
||
14. Проверяет архив и прогоняет acceptance-проверки.
|
||
|
||
## Версия Hysteria: разрешение и compatibility gate
|
||
|
||
Builder не хранит версию Hysteria вручную. По умолчанию он определяет последнюю стабильную версию сам и замораживает её в пакете.
|
||
|
||
Правила разрешения:
|
||
|
||
1. канонический upstream — `HyNetworks/hysteria`;
|
||
2. принимаются только стабильные релизы, без draft и prerelease;
|
||
3. тег должен иметь вид `app/vX.Y.Z`;
|
||
4. берётся ровно один артефакт `hysteria-linux-amd64`;
|
||
5. URL используется в том виде, в каком его вернул upstream API, без пересборки строки;
|
||
6. SHA-256 считается локально от скачанного файла;
|
||
7. разрешённые значения попадают в metadata пакета.
|
||
|
||
Сравнение версий числовое, поэтому `v2.9.10` считается новее `v2.9.2`.
|
||
|
||
После разрешения обязателен compatibility gate:
|
||
|
||
```text
|
||
скачать бинарник
|
||
↓
|
||
сверить SHA-256 и `hysteria version`
|
||
↓
|
||
отрендерить канонический конфиг HY2XS тем же кодом, что и на target
|
||
↓
|
||
запустить настоящий Hysteria с этим конфигом (gecko и salamander)
|
||
↓
|
||
только после этого собирать release package
|
||
```
|
||
|
||
При несовместимости сборка останавливается:
|
||
|
||
```text
|
||
BUILD FAILED: unsupported Hysteria stable v2.13.0
|
||
```
|
||
|
||
Это осознанное решение: ошибка должна проявиться на build machine, а не на production-сервере.
|
||
|
||
Переменные:
|
||
|
||
| Переменная | По умолчанию | Назначение |
|
||
| --- | --- | --- |
|
||
| `HYSTERIA_CHANNEL` | `stable` | `stable` — разрешить последнюю стабильную через upstream API; `pinned` — офлайн-сборка по `hysteria-lock.env` |
|
||
| `HYSTERIA_VERSION_OVERRIDE` | пусто | Закрепить конкретную версию `vX.Y.Z` |
|
||
| `HYSTERIA_COMPAT_GATE` | `true` | Compatibility gate; для release-сборок обязателен |
|
||
| `HYSTERIA_WRITE_LOCK` | `false` | Записать разрешённые значения обратно в `hysteria-lock.env` |
|
||
| `HYSTERIA_GATE_PORT` | `34443` | UDP-порт для временного запуска Hysteria в gate |
|
||
| `HYSTERIA_GATE_STATS_PORT` | `34712` | TCP-порт trafficStats в gate |
|
||
| `GITHUB_TOKEN` | пусто | Опционально: снимает anonymous rate limit GitHub API |
|
||
| `SKIP_TESTS` | `false` | Аварийное отключение тестов; для release-сборок недопустимо |
|
||
|
||
Обновить lock-файл под текущий upstream:
|
||
|
||
```bash
|
||
HYSTERIA_WRITE_LOCK=true ./tools/build/build.sh
|
||
```
|
||
|
||
## Важное про Bun и старые CPU
|
||
|
||
Bun имеет два Linux x64 artifact'а:
|
||
|
||
- `bun-linux-x64` — обычный build;
|
||
- `bun-linux-x64-baseline` — build для CPU без AVX2.
|
||
|
||
Если CPU не поддерживает AVX2, обычный Bun может падать с `Illegal instruction`.
|
||
|
||
Builder автоматически проверяет `/proc/cpuinfo`.
|
||
|
||
По умолчанию:
|
||
|
||
```bash
|
||
BUN_FLAVOR=auto
|
||
```
|
||
|
||
Логика:
|
||
|
||
- если CPU поддерживает AVX2, используется `bun-linux-x64`;
|
||
- если CPU не поддерживает AVX2, используется `bun-linux-x64-baseline`.
|
||
|
||
Можно принудительно задать flavor:
|
||
|
||
```bash
|
||
BUN_FLAVOR=x64 ./tools/build/build.sh
|
||
```
|
||
|
||
или:
|
||
|
||
```bash
|
||
BUN_FLAVOR=x64-baseline ./tools/build/build.sh
|
||
```
|
||
|
||
## Запуск
|
||
|
||
Из корня репозитория:
|
||
|
||
```bash
|
||
./tools/build/build.sh
|
||
```
|
||
|
||
С явной версией и build id:
|
||
|
||
```bash
|
||
PACKAGE_VERSION=1.0.0 \
|
||
BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ) \
|
||
./tools/build/build.sh
|
||
```
|
||
|
||
## Проверка результата
|
||
|
||
Проверка архива:
|
||
|
||
```bash
|
||
ls -lh dist/hy2xs-install-1.0.0.tar.gz
|
||
sha256sum dist/hy2xs-install-1.0.0.tar.gz | tee dist/hy2xs-install-1.0.0.tar.gz.sha256
|
||
```
|
||
|
||
Проверка обязательных файлов:
|
||
|
||
```bash
|
||
tar -tzf dist/hy2xs-install-1.0.0.tar.gz | grep -E '^(hy2xs-install/install.sh|hy2xs-install/orchestrator/hy2xs-orchestrator|hy2xs-install/ui/hy2xs-admin/hy2xs-admin|hy2xs-install/metadata/checksums.txt)$'
|
||
```
|
||
|
||
Проверка metadata:
|
||
|
||
```bash
|
||
tar -xOzf dist/hy2xs-install-1.0.0.tar.gz hy2xs-install/metadata/package.env
|
||
```
|
||
|
||
## Когда обновлять orchestrator/bun.lock
|
||
|
||
Не перегенерируйте [`orchestrator/bun.lock`](../../orchestrator/bun.lock) во время production-сборки.
|
||
|
||
Обновлять и коммитить [`orchestrator/bun.lock`](../../orchestrator/bun.lock) следует только когда:
|
||
|
||
- изменился [`orchestrator/package.json`](../../orchestrator/package.json);
|
||
- изменился `BUN_REQUIRED` в [`tools/build/lib/deps.sh`](lib/deps.sh);
|
||
- зависимости оркестратора обновляются осознанно.
|
||
|
||
Production builder всегда выполняет:
|
||
|
||
```bash
|
||
bun install --frozen-lockfile
|
||
```
|
||
|
||
Если команда падает, исправьте и закоммитьте lockfile в системе контроля версий. Не убирайте `--frozen-lockfile`.
|
||
|
||
## Дисциплина lockfile для frontend
|
||
|
||
Не перегенерируйте frontend lock data во время обычной production-сборки.
|
||
|
||
Правила управления пакетами frontend:
|
||
|
||
- [`apps/frontend/package.json`](../../apps/frontend/package.json) объявляет `"packageManager": "pnpm@9.15.9"`;
|
||
- builder использует закреплённый pnpm `9.15.9` из [`PNPM_REQUIRED`](lib/deps.sh);
|
||
- production-путь установки frontend всегда:
|
||
|
||
```bash
|
||
pnpm install --frozen-lockfile
|
||
```
|
||
|
||
Если frozen install падает, обновите зависимости осознанно в системе контроля версий и закоммитьте изменения lockfile. Не убирайте `--frozen-lockfile` из сборочного потока.
|
||
|
||
## Полезные переменные
|
||
|
||
- `PACKAGE_VERSION=1.0.0`
|
||
- `BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ)`
|
||
- `BUN_FLAVOR=auto|x64|x64-baseline`
|
||
- `FRONTEND_NODE_OLD_SPACE_SIZE=2048` (default memory limit for frontend build step)
|
||
- `TOOLCHAIN_DIR=/custom/path/.toolchain`
|
||
- `VERIFY_TOOLCHAIN_CHECKSUMS=true`
|
||
|
||
По умолчанию `VERIFY_TOOLCHAIN_CHECKSUMS=true` в [`tools/build/lib/deps.sh`](lib/deps.sh), поэтому для production-сборки обязательно передавать контрольные суммы:
|
||
|
||
- `GO_ARCHIVE_SHA256=<sha256>`
|
||
- `NODE_ARCHIVE_SHA256=<sha256>`
|
||
- `BUN_ARCHIVE_SHA256=<sha256>`
|
||
|
||
## Политика памяти при сборке frontend
|
||
|
||
Builder задаёт безопасный лимит heap для Node.js внутри [`bundle_ui()`](lib/package.sh):
|
||
|
||
```bash
|
||
--max-old-space-size=2048
|
||
```
|
||
|
||
Способы переопределения:
|
||
|
||
- изменить значение по умолчанию для этой политики:
|
||
|
||
```bash
|
||
FRONTEND_NODE_OLD_SPACE_SIZE=3072 ./tools/build/build.sh
|
||
```
|
||
|
||
- или передать полный набор собственных Node-опций (если `--max-old-space-size` там уже задан, builder не добавит второй):
|
||
|
||
```bash
|
||
NODE_OPTIONS="--max-old-space-size=3072" ./tools/build/build.sh
|
||
```
|
||
|
||
## Диагностика
|
||
|
||
Проверить AVX2:
|
||
|
||
```bash
|
||
grep -m1 '^flags' /proc/cpuinfo | grep -qw avx2 && echo 'CPU has AVX2' || echo 'CPU has NO AVX2; Bun baseline is required'
|
||
```
|
||
|
||
Проверить Bun:
|
||
|
||
```bash
|
||
.toolchain/bun/bin/bun --version
|
||
echo "bun_exit=$?"
|
||
```
|
||
|
||
Если есть `Illegal instruction`, удалите старый Bun и пересоберите:
|
||
|
||
```bash
|
||
rm -rf .toolchain/bun .toolchain/bun-tmp
|
||
rm -f .toolchain/downloads/bun-linux-x64-*.zip
|
||
rm -f .toolchain/downloads/bun-linux-x64-baseline-*.zip
|
||
PACKAGE_VERSION=1.0.0 ./tools/build/build.sh
|
||
```
|
||
|
||
Проверить shell syntax:
|
||
|
||
```bash
|
||
bash -n tools/build/build.sh
|
||
bash -n tools/build/lib/common.sh
|
||
bash -n tools/build/lib/deps.sh
|
||
bash -n tools/build/lib/package.sh
|
||
bash -n tools/build/lib/verify.sh
|
||
```
|