feat(v1): Gecko-обфускация, latest-stable Hysteria на сборке и forward-compatible admin

Сквозная миграция 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 файлов),
документация на русском.
This commit is contained in:
2026-08-27 08:15:02 +05:00
parent 0205334cd8
commit ddf0ddf71e
53 changed files with 4827 additions and 291 deletions
+111 -8
View File
@@ -13,7 +13,9 @@
<a href="#возможности">Возможности</a> ·
<a href="#быстрый-старт-для-нового-сервера">Быстрый старт</a> ·
<a href="#конфигурация-hy2xsenv">Конфигурация</a> ·
<a href="#версионная-политика-hysteria2">Версии</a> ·
<a href="#сборка-release-пакета">Сборка</a> ·
<a href="CHANGELOG.md">Changelog</a> ·
<a href="#лицензия">Лицензия</a>
</p>
@@ -39,7 +41,7 @@ HY2XS подходит для сценария, где нужен один produ
HY2XS release‑пакет разворачивает и настраивает:
- официальный upstream‑бинарник Hysteria2, закреплённый в metadata пакета и проверяемый по SHA256;
- официальный upstream‑бинарник Hysteria2: последняя стабильная версия выбирается при сборке пакета, закрепляется в его metadata и проверяется по SHA256;
- HY2XS admin — встроенную админ‑панель для управления users/peers, трафиком, конфигурацией, логами и состоянием сервера;
- systemd‑юнит `hysteria-server` для Hysteria2;
- systemd‑юнит `hy2xs-admin` для админ‑панели;
@@ -108,6 +110,8 @@ Windows и macOS можно использовать для разработки
- не включает IPv6production baseline;
- не настраивает `sshd` автоматически;
- не предоставляет полноценный uninstall/update framework;
- не обновляет Hysteria2 на уже работающем сервере: `reconfigure` намеренно не является Hysteria updater;
- не мигрирует установки `0.x` на `1.0.0` — переход выполняется чистой установкой, см. [CHANGELOG](CHANGELOG.md);
- не выполняет сложную миграцию старых неизвестных состояний сервера;
- не реализует Telegram‑бота, port hopping и универсальный accessdelivery workflow;
- не предназначен для установки поверх давно используемого сервера с неизвестными firewall/systemd‑правками.
@@ -147,10 +151,74 @@ hy2xs-install/
| TrafficStats Hysteria2 | `127.0.0.1:36712` |
| Firewall mode | `takeover` в packaged baseline |
| Hysteria2 auth | `http` через локальный HY2XS admin |
| Hysteria2 obfs | `salamander` |
| Hysteria2 obfs | `gecko` (512/1200); `salamander` доступен как режим совместимости |
| Congestion fallback | `bbr`, профиль `standard` |
| QUIC stateless reset | включён |
Важно: `HY2XS_SSH_PORT` нужен HY2XS для nftables‑правил и проверки доступности SSH‑порта. Сам `sshd` проект не перенастраивает. SSH на `2323` и вход только по ключу нужно настроить до запуска `./install.sh`.
## Версионная политика Hysteria2
HY2XS **не привязан к конкретному номеру версии Hysteria**.
> Источник по умолчанию берёт последний стабильный релиз Hysteria, доступный на момент сборки пакета. Разрешённая версия, URL артефакта и контрольная сумма замораживаются в получившемся install‑пакете.
Как это работает:
```text
build machine target server
───────────── ─────────────
определить последнюю стабильную ─┐
скачать артефакт, посчитать SHA-256 │
проверить, что бинарник принимает ├─► release‑пакет ──► скачать ровно
канонический конфиг HY2XS │ version + url этот артефакт,
заморозить version/url/sha256 ─┘ + sha256 сверить SHA-256
и `hysteria version`
```
Что это даёт:
- новая установка получает актуальную Hysteria без ручного обновления version lock;
- если между сборкой пакета и его установкой выйдет новая версия, **содержимое установки не изменится**;
- повторная установка старого пакета поставит ту же версию, что и в день сборки;
- несовместимый upstream ломает сборку, а не сервер оператора.
Переопределения при сборке:
```bash
# по умолчанию: последняя стабильная
./tools/build/build.sh
# закрепить конкретную версию
HYSTERIA_VERSION_OVERRIDE=v2.12.2 ./tools/build/build.sh
# офлайн-сборка по закоммиченному tools/build/hysteria-lock.env
HYSTERIA_CHANNEL=pinned ./tools/build/build.sh
```
Фактически установленная версия видна в `/etc/hysteria/post-install.env` (`HY2_VERSION`), а способ её выбора — в `HY2_RESOLUTION`.
Обновление Hysteria на уже работающем сервере в текущем релизе не поддерживается: `reconfigure` намеренно не является Hysteria updater. Это сохраняет immutable‑контракт развёртывания.
## Обфускация
Новые установки HY2XS используют **Gecko**.
Gecko помечен upstream как **experimental**. Он достраивается поверх Salamander: помимо scramble он дополнительно фрагментирует QUIC handshake на пакеты случайного размера. HY2XS использует upstream‑defaults размеров пакетов `512/1200` как проверенный production‑профиль.
**Salamander остаётся поддержанным режимом совместимости.** Смена типа обфускации требует соответствующих изменений на клиенте: это изменение wire‑совместимости, а не косметическая настройка.
| | Gecko | Salamander |
| --- | --- | --- |
| Статус upstream | experimental | stable |
| Роль в HY2XS | default для новых установок | режим совместимости |
| Параметр | `HY2XS_HYSTERIA_OBFS_TYPE=gecko` | `HY2XS_HYSTERIA_OBFS_TYPE=salamander` |
| В клиентской ссылке | `obfs=gecko` | `obfs=salamander` |
Экспериментальность upstream остаётся контролируемым риском, потому что одновременно выполняются три условия: Salamander доступен как fallback, каждая разрешённая версия проходит compatibility gate до выпуска пакета, и существующие серверы никогда не переводятся на Gecko молча.
Размеры пакетов Gecko не выносятся в конфигурацию: официальная схема `hysteria2://` не умеет их передавать, поэтому нестандартные значения сделали бы клиентскую ссылку неполной.
## Быстрый старт для нового сервера
Ниже приведён полный путь для оператора, который работает с Windows и ставит HY2XS на чистый Debian 13 сервер.
@@ -379,10 +447,12 @@ HY2XS_IPV6_ENABLED=false
HY2XS_TLS_MODE=acme
HY2XS_ACME_TYPE=http
HY2XS_HYSTERIA_AUTH_MODE=http
HY2XS_HYSTERIA_OBFS_TYPE=salamander
HY2XS_HYSTERIA_OBFS_TYPE=gecko
HY2XS_UI_PUBLIC_ACCESS=false
```
Если нужен режим совместимости со старыми клиентами, укажите `HY2XS_HYSTERIA_OBFS_TYPE=salamander`. Подробнее — в разделе [Обфускация](#обфускация).
### 9. Запустите установку
```bash
@@ -396,7 +466,7 @@ HY2XS_UI_PUBLIC_ACCESS=false
3. создаст runtime‑каталоги и service users;
4. запишет `/etc/hy2xs/hy2xs.env`;
5. разложит bundled HY2XS admin;
6. скачает pinned Hysteria2 binary из upstream и проверит SHA256;
6. скачает закреплённый в пакете Hysteria2 binary из upstream, проверит SHA256 и фактическую версию;
7. создаст `/etc/hysteria/config.yaml`;
8. установит systemd‑юниты;
9. применит nftables‑правила;
@@ -507,6 +577,7 @@ hy2xs-orchestrator status \
| Переменная | Назначение | Значение по умолчанию в packaged baseline |
| --- | --- | --- |
| `HY2XS_CONFIG_SCHEMA_VERSION` | Версия схемы конфигурации HY2XS. Конфигурация другой схемы отклоняется fail‑fast | `2` |
| `HY2XS_IPV6_ENABLED` | IPv6‑режим. В production baseline должен быть `false` | `false` |
| `HY2XS_DOMAIN` | Домен для ACME и deploy‑профиля | `fi.api.withen.pro` |
| `HY2XS_DNS_AAAA_POLICY` | Поведение при наличии AAAA‑записи: `strict`, `warn`, `off` | `strict` |
@@ -534,8 +605,8 @@ hy2xs-orchestrator status \
| `HY2XS_HYSTERIA_TRAFFIC_STATS_HOST` | Host trafficStats API | `127.0.0.1` |
| `HY2XS_HYSTERIA_TRAFFIC_STATS_PORT` | Порт trafficStats API | `36712` |
| `HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET` | Secret для trafficStats и machine auth | `__GENERATE__` |
| `HY2XS_HYSTERIA_OBFS_TYPE` | Obfuscation type. Фиксированное значение production‑профиля | `salamander` |
| `HY2XS_HYSTERIA_OBFS_PASSWORD` | Salamander password | `__GENERATE__` |
| `HY2XS_HYSTERIA_OBFS_TYPE` | Тип обфускации: `gecko` или `salamander`. Смена меняет wire‑совместимость | `gecko` |
| `HY2XS_HYSTERIA_OBFS_PASSWORD` | Пароль обфускации; `__GENERATE__` генерируется при install | `__GENERATE__` |
| `HY2XS_HYSTERIA_BANDWIDTH_UP` | Hysteria2 upstream bandwidth | `50 mbps` |
| `HY2XS_HYSTERIA_BANDWIDTH_DOWN` | Hysteria2 downstream bandwidth | `50 mbps` |
| `HY2XS_HYSTERIA_IGNORE_CLIENT_BANDWIDTH` | Игнорировать bandwidth клиента | `false` |
@@ -717,7 +788,7 @@ git status --short
Подготовьте build env:
```bash
export PACKAGE_VERSION=0.2.2
export PACKAGE_VERSION=1.0.0
export BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ)
# Для переносимости между x86_64-серверами без AVX2 предпочтителен baseline artifact.
@@ -728,6 +799,9 @@ export BUN_FLAVOR=x64-baseline
export GO_ARCHIVE_SHA256=<sha256-go1.21.13-linux-amd64.tar.gz>
export NODE_ARCHIVE_SHA256=<sha256-node-v20.19.0-linux-x64.tar.xz>
export BUN_ARCHIVE_SHA256=<sha256-bun-linux-x64-baseline-1.3.13.zip>
# Опционально: снимает anonymous rate limit при разрешении upstream-релиза.
export GITHUB_TOKEN=<token>
```
Запустите сборку:
@@ -736,6 +810,32 @@ export BUN_ARCHIVE_SHA256=<sha256-bun-linux-x64-baseline-1.3.13.zip>
./tools/build/build.sh
```
Сборка последовательно:
1. прогоняет тесты и типы оркестратора (`bun test`, `tsc --noEmit`);
2. определяет последнюю стабильную версию Hysteria, скачивает артефакт и считает SHA‑256;
3. проходит compatibility gate: реальный бинарник Hysteria должен принять канонический конфиг HY2XS для Gecko и для Salamander;
4. собирает orchestrator, frontend и backend;
5. прогоняет `go vet` и `go test` для HY2XS admin;
6. формирует архив и прогоняет acceptance‑проверки.
Любой сбой на шагах 1–5 останавливает сборку до создания пакета.
Переменные, управляющие выбором версии Hysteria:
| Переменная | По умолчанию | Назначение |
| --- | --- | --- |
| `HYSTERIA_CHANNEL` | `stable` | `stable` — разрешить последнюю стабильную; `pinned` — офлайн‑сборка по `tools/build/hysteria-lock.env` |
| `HYSTERIA_VERSION_OVERRIDE` | пусто | Закрепить конкретную версию `vX.Y.Z` |
| `HYSTERIA_COMPAT_GATE` | `true` | Compatibility gate; для release‑сборок обязателен |
| `HYSTERIA_WRITE_LOCK` | `false` | Записать разрешённые значения обратно в lock‑файл |
Полный E2E с реальным клиентом Hysteria запускается отдельно:
```bash
HYSTERIA_BIN=/usr/local/bin/hysteria ./tools/test/e2e-hysteria.sh
```
Результат:
```text
@@ -748,7 +848,7 @@ dist/hy2xs-install-<version>.tar.gz
ls -lh dist/hy2xs-install-*.tar.gz
sha256sum dist/hy2xs-install-*.tar.gz
tar -tzf dist/hy2xs-install-0.2.2.tar.gz | grep -E \
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)$'
```
@@ -762,6 +862,9 @@ tar -tzf dist/hy2xs-install-0.2.2.tar.gz | grep -E \
├── orchestrator/ # install-only orchestrator на Bun + TypeScript
├── package/ # skeleton будущего install package
├── tools/build/ # production builder и packaging pipeline
├── tools/test/ # end-to-end проверки с реальным клиентом Hysteria
├── docs/ # спецификации baseline, тестов и эксплуатации
├── CHANGELOG.md
├── README.md
└── LICENSE
```