Files
HY2XS_flamy/README.md
T
founder ddf0ddf71e 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 файлов),
документация на русском.
2026-08-27 08:15:02 +05:00

898 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HY2XS Core
<p align="center">
<img src="apps/frontend/src/assets/logo.png" width="96" alt="HY2XS logo">
</p>
<p align="center">
<b>HY2XS</b> — production‑установщик Hysteria2‑сервера с локальной HY2XS admin‑панелью, systemd‑юнитами, nftablesfirewall и воспроизводимой моделью release‑пакета для чистого Debian 13.
</p>
<p align="center">
<a href="#что-это">Что это</a> ·
<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>
<p align="center">
<img alt="Target OS" src="https://img.shields.io/badge/target-Debian%2013-A81D33">
<img alt="Architecture" src="https://img.shields.io/badge/arch-amd64%20%2F%20x86__64-555555">
<img alt="Firewall" src="https://img.shields.io/badge/firewall-nftables-2563eb">
<img alt="Runtime" src="https://img.shields.io/badge/runtime-systemd-111827">
<img alt="License" src="https://img.shields.io/badge/license-AGPL--3.0--only-green">
</p>
---
## Что это
HY2XS — это install‑only пакет для развёртывания Hysteria2‑узла на чистом Debian 13 amd64. Проект разделяет сборку и установку: разработчик один раз собирает release‑архив на Debian 13 build‑хосте, а целевой сервер получает уже готовый пакет и запускает `install.sh` без `git clone`, `go build`, `bun install`, `pnpm install` и сборки frontend‑ассетов.
HY2XS подходит для сценария, где нужен один production‑сервер с Hysteria2, локальной админ‑панелью, управляемым firewall и предсказуемой конфигурацией. Проект не является универсальным server manager, update manager или панелью для любых Linux‑дистрибутивов.
Ключевая идея: на target‑сервере выполняется только установка готового пакета. Вся тяжёлая сборочная часть остаётся на build‑машине.
## Возможности
HY2XS release‑пакет разворачивает и настраивает:
- официальный upstream‑бинарник Hysteria2: последняя стабильная версия выбирается при сборке пакета, закрепляется в его metadata и проверяется по SHA256;
- HY2XS admin — встроенную админ‑панель для управления users/peers, трафиком, конфигурацией, логами и состоянием сервера;
- systemd‑юнит `hysteria-server` для Hysteria2;
- systemd‑юнит `hy2xs-admin` для админ‑панели;
- runtime‑конфиг `/etc/hy2xs/hy2xs.env`;
- Hysteria2‑конфиг `/etc/hysteria/config.yaml`;
- postinstall snapshot `/etc/hysteria/post-install.env`;
- bootstrap‑секреты администратора в `/etc/hy2xs/bootstrap-admin.secret`;
- nftables‑правила с staged apply и rollback guard;
- smoke‑проверки после установки;
- команды диагностики, статуса, реконфигурации и сбора supportbundle.
HY2XS admin запускается локально по умолчанию на `127.0.0.1:8080`. Наружу публикуется Hysteria2‑транспорт, а доступ к панели выполняется через SSH local port forwarding.
## Архитектура
```mermaid
graph LR
operator[Оператор на Windows/Linux/macOS] -->|SSH 2323/tcp| ssh[sshd на target]
operator -->|SSH tunnel 127.0.0.1:8080| ui[HY2XS admin 127.0.0.1:8080]
internet[Интернет] -->|443/udp| hy2[Hysteria2 server]
letsencrypt[Let's Encrypt] -->|80/tcp при ACME http| acme[ACME challenge]
hy2 -->|HTTP auth localhost + machine token| ui
ui -->|trafficStats localhost| hy2
hy2 --> cfg["/etc/hysteria/config.yaml"]
ui --> env["/etc/hy2xs/hy2xs.env"]
fw[nftables] --> ssh
fw --> hy2
fw --> acme
```
В production‑профиле проект работает как IPv4only stack. IPv6 намеренно не входит в текущий baseline. Если у домена есть AAAA‑запись и включён строгий режим `HY2XS_DNS_AAAA_POLICY=strict`, установка останавливается до применения конфигурации.
## Поддерживаемые платформы
### Target‑сервер
| Компонент | Поддерживается |
| --- | --- |
| ОС | Debian 13 |
| Архитектура | amd64 / x86_64 |
| Init system | systemd |
| Firewall | nftables |
| Сетевой профиль | IPv4‑only |
| Hysteria2 target | linuxamd64 |
| Admin UI | локальный bind по умолчанию: `127.0.0.1:8080` |
### Build‑машина
| Компонент | Поддерживается |
| --- | --- |
| ОС | Debian 13 |
| Архитектура | amd64 / x86_64 |
| Git tree | обязателен |
| Dirty tree | запрещён по умолчанию |
| Интернет | нужен для apt, Go, Bun, Node.js, pnpm/npm registry, GitHub и upstream Hysteria2 |
Windows и macOS можно использовать для разработки, редактирования кода и работы с GitHub, но production‑архив должен собираться на Debian 13 amd64.
## Что HY2XS не делает
Это важные границы проекта:
- не собирает проект на target‑сервере;
- не поддерживает Debian 12, Ubuntu, CentOS, Alpine и другие ОС;
- не поддерживает arm64 в текущем release‑профиле;
- не включает 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‑правками.
## Release‑пакет
Production‑сборка создаёт один архив:
```text
hy2xs-install-<version>.tar.gz
```
Внутри архива находятся:
```text
hy2xs-install/
├── install.sh
├── orchestrator/hy2xs-orchestrator
├── ui/hy2xs-admin/hy2xs-admin
├── config/hy2xs.env
├── templates/
├── systemd/
├── docs/
└── metadata/
```
При запуске `install.sh` пакет проверяет `metadata/checksums.txt`, устанавливает orchestrator в `/usr/local/lib/hy2xs/hy2xs-orchestrator`, создаёт symlink `/usr/local/bin/hy2xs-orchestrator`, копирует package assets в `/usr/local/lib/hy2xs/package` и передаёт управление installonly orchestrator.
## Сетевая модель по умолчанию
| Назначение | Значение по умолчанию |
| --- | --- |
| SSH оператора | `2323/tcp` |
| Hysteria2 | `443/udp` |
| ACME HTTP challenge | `80/tcp`, если `HY2XS_TLS_MODE=acme` и `HY2XS_ACME_TYPE=http` |
| HY2XS admin | `127.0.0.1:8080` |
| TrafficStats Hysteria2 | `127.0.0.1:36712` |
| Firewall mode | `takeover` в packaged baseline |
| Hysteria2 auth | `http` через локальный HY2XS admin |
| 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 сервер.
В примерах используются условные значения:
| Параметр | Пример |
| --- | --- |
| IP сервера | `SERVER_IP` |
| Домен сервера | `vpn.example.com` |
| Email для ACME | `admin@example.com` |
| Release‑архив | `hy2xs-install-0.2.2.tar.gz` |
| SSH‑ключ | `id_ed25519_hy2xs` |
Замените эти значения на свои.
### 1. Проверьте DNS и внешние порты
До установки домен должен указывать A‑записью на IPv4‑адрес target‑сервера:
```text
vpn.example.com -> SERVER_IP
```
Для стандартной установки с `HY2XS_TLS_MODE=acme` и `HY2XS_ACME_TYPE=http` снаружи должны быть доступны:
| Порт | Протокол | Назначение |
| --- | --- | --- |
| `2323` | TCP | SSH оператора |
| `80` | TCP | ACME HTTP challenge |
| `443` | UDP | Hysteria2 |
Если у домена есть AAAA‑запись, при строгой политике `HY2XS_DNS_AAAA_POLICY=strict` установка будет остановлена, потому что текущий production‑профиль HY2XS является IPv4only.
### 2. Создайте SSH‑ключ на Windows
Откройте PowerShell:
```powershell
ssh-keygen -t ed25519 -a 100 -f "$env:USERPROFILE\.ssh\id_ed25519_hy2xs" -C "hy2xs-target-1"
```
Выведите публичный ключ:
```powershell
type "$env:USERPROFILE\.ssh\id_ed25519_hy2xs.pub"
```
Скопируйте всю строку вида:
```text
ssh-ed25519 AAAA... hy2xs-target-1
```
Именно её нужно добавить на сервер в `/root/.ssh/authorized_keys`.
### 3. Войдите на сервер по паролю провайдера
Первый вход обычно выполняется по временному root‑паролю от провайдера:
```powershell
ssh root@SERVER_IP
```
На сервере установите базовые пакеты:
```bash
apt-get update
apt-get install -y openssh-server sudo ca-certificates curl tar
```
### 4. Добавьте публичный ключ на сервер
На сервере замените пример ключа на свой реальный публичный ключ:
```bash
install -d -m 700 -o root -g root /root/.ssh
cat > /root/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAA_REPLACE_WITH_YOUR_PUBLIC_KEY hy2xs-target-1
EOF
chmod 600 /root/.ssh/authorized_keys
chown -R root:root /root/.ssh
```
### 5. Переведите SSH на порт 2323 и отключите парольный вход
Не закрывайте текущую SSH‑сессию, пока не проверите новый вход по ключу.
Сначала посмотрите, какие SSH‑директивы уже заданы провайдером:
```bash
grep -RniE '^[[:space:]]*(Include|Port|PermitRootLogin|PasswordAuthentication|KbdInteractiveAuthentication|ChallengeResponseAuthentication|PubkeyAuthentication|AllowTcpForwarding|PermitOpen|GatewayPorts|Match)\b' \
/etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true
```
OpenSSH для многих параметров использует первое найденное значение. Поэтому поздний файл вида `99-*.conf` может не перекрыть ранний provider‑конфиг. Безопаснее сначала закомментировать конфликтующие директивы, затем создать ранний `00-hy2xs-operator.conf`.
```bash
for f in /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf; do
[ -f "$f" ] || continue
cp -a "$f" "$f.bak.$(date +%Y%m%d-%H%M%S)"
sed -i -E 's/^[[:space:]]*(Port|PermitRootLogin|PasswordAuthentication|KbdInteractiveAuthentication|ChallengeResponseAuthentication|PubkeyAuthentication|AllowTcpForwarding|PermitOpen|GatewayPorts|X11Forwarding|AllowAgentForwarding|MaxAuthTries|LoginGraceTime|ClientAliveInterval|ClientAliveCountMax)[[:space:]]+/# disabled-by-hy2xs-hardening: &/' "$f"
done
cat > /etc/ssh/sshd_config.d/00-hy2xs-operator.conf <<'EOF'
Port 2323
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin prohibit-password
AllowTcpForwarding local
PermitOpen 127.0.0.1:8080 localhost:8080
GatewayPorts no
X11Forwarding no
AllowAgentForwarding no
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
EOF
sshd -t
systemctl reload ssh || systemctl restart ssh
```
Проверьте effective‑конфиг:
```bash
sshd -T | grep -E '^(port|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|allowtcpforwarding|permitopen|gatewayports) '
ss -H -ltn | grep -E ':(22|2323) '
```
Ожидаемо:
```text
port 2323
permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
gatewayports no
allowtcpforwarding local
permitopen 127.0.0.1:8080 localhost:8080
```
В списке listen‑портов должен остаться `2323`, а `22` не должен слушаться.
### 6. Проверьте вход по ключу
В новом PowerShell‑окне:
```powershell
ssh -p 2323 -i "$env:USERPROFILE\.ssh\id_ed25519_hy2xs" root@SERVER_IP
```
Проверьте, что парольный вход запрещён:
```powershell
ssh -p 2323 -o PreferredAuthentications=password -o PubkeyAuthentication=no root@SERVER_IP
```
Правильный результат:
```text
Permission denied (publickey).
```
После этого можно дополнительно заблокировать пароль root на уровне Linux‑аккаунта:
```bash
passwd -l root
passwd -S root
```
Это не ломает вход по SSH‑ключу, но защищает от случайного возврата парольной SSH‑аутентификации в будущем.
### 7. Скопируйте release‑архив на сервер
С Windows:
```powershell
scp -P 2323 -i "$env:USERPROFILE\.ssh\id_ed25519_hy2xs" .\hy2xs-install-0.2.2.tar.gz root@SERVER_IP:/root/
```
На сервере:
```bash
cd /root
tar -xzf hy2xs-install-0.2.2.tar.gz
cd /root/hy2xs-install
```
### 8. Создайте конфиг для своего сервера
Не редактируйте исходный шаблон внутри пакета без необходимости. Создайте отдельный sourceconfig:
```bash
cp config/hy2xs.env /root/hy2xs-target.env
nano /root/hy2xs-target.env
```
Минимально проверьте и измените:
```env
HY2XS_DOMAIN=vpn.example.com
HY2XS_PUBLIC_HOST=vpn.example.com
HY2XS_ACME_EMAIL=admin@example.com
HY2XS_SSH_PORT=2323
HY2XS_UI_BIND_HOST=127.0.0.1
HY2XS_UI_PORT=8080
HY2XS_HYSTERIA_PORT=443
HY2XS_FIREWALL_MODE=takeover
HY2XS_FIREWALL_STAGED_APPLY=true
```
Для стандартной production‑установки оставьте:
```env
HY2XS_IPV6_ENABLED=false
HY2XS_TLS_MODE=acme
HY2XS_ACME_TYPE=http
HY2XS_HYSTERIA_AUTH_MODE=http
HY2XS_HYSTERIA_OBFS_TYPE=gecko
HY2XS_UI_PUBLIC_ACCESS=false
```
Если нужен режим совместимости со старыми клиентами, укажите `HY2XS_HYSTERIA_OBFS_TYPE=salamander`. Подробнее — в разделе [Обфускация](#обфускация).
### 9. Запустите установку
```bash
./install.sh --config /root/hy2xs-target.env --non-interactive
```
Во время установки HY2XS:
1. проверит checksums release‑пакета;
2. установит orchestrator в `/usr/local/lib/hy2xs`;
3. создаст runtime‑каталоги и service users;
4. запишет `/etc/hy2xs/hy2xs.env`;
5. разложит bundled HY2XS admin;
6. скачает закреплённый в пакете Hysteria2 binary из upstream, проверит SHA256 и фактическую версию;
7. создаст `/etc/hysteria/config.yaml`;
8. установит systemd‑юниты;
9. применит nftables‑правила;
10. выполнит smokechecks;
11. зафиксирует успешное состояние в `/var/lib/hy2xs/install-state.json`.
### 10. Получите bootstrap‑пароль админки
```bash
cat /etc/hy2xs/bootstrap-admin.secret
```
Файл содержит:
```env
ADMIN_USER=...
ADMIN_INITIAL_PASSWORD=...
ADMIN_CON_PASS=...
```
`ADMIN_INITIAL_PASSWORD` нужен для первого входа в HY2XS admin. После первого входа смените пароль через интерфейс.
`ADMIN_CON_PASS` — bootstrap‑секрет Hysteria2 peer/auth слоя. Не публикуйте этот файл и не отправляйте его в issue/log без редактирования.
### 11. Откройте HY2XS admin через SSH‑туннель
На локальной машине:
```powershell
ssh -p 2323 `
-i "$env:USERPROFILE\.ssh\id_ed25519_hy2xs" `
-N `
-L 127.0.0.1:8080:127.0.0.1:8080 `
root@SERVER_IP
```
Пример для Linux/macOS (одной строкой):
```bash
ssh -p 2323 -i ~/.ssh/id_ed25519_hy2xs -N -L 8080:127.0.0.1:8080 root@SERVER_IP
```
После этого откройте в браузере:
```text
http://127.0.0.1:8080/
```
Если порт `8080` на локальной машине занят, можно пробросить другой локальный порт:
```powershell
ssh -p 2323 `
-i "$env:USERPROFILE\.ssh\id_ed25519_hy2xs" `
-N `
-L 127.0.0.1:18080:127.0.0.1:8080 `
root@SERVER_IP
```
И открыть:
```text
http://127.0.0.1:18080/
```
### 12. Проверьте установку
На сервере:
```bash
systemctl status hysteria-server --no-pager
systemctl status hy2xs-admin --no-pager
ss -H -lun | grep ':443'
ss -H -ltn | grep ':8080'
ss -H -ltn | grep ':2323'
nft list ruleset
cat /var/lib/hy2xs/install-state.json
```
Выполните doctor‑проверку:
```bash
hy2xs-orchestrator doctor \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env
```
Проверьте сводный статус:
```bash
hy2xs-orchestrator status \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env
```
## Конфигурация `hy2xs.env`
После установки основным редактируемым файлом является:
```text
/etc/hy2xs/hy2xs.env
```
Менять runtime‑параметры нужно через этот файл и затем применять `reconfigure`. Редактирование `post-install.env` не меняет runtime‑состояние.
### Основные параметры
| Переменная | Назначение | Значение по умолчанию в 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` |
| `HY2XS_PUBLIC_HOST` | Публичный host без схемы, порта и path | `fi.api.withen.pro` |
| `HY2XS_PUBLIC_PORT` | Публичный порт Hysteria2 endpoint | `443` |
| `HY2XS_SSH_PORT` | SSH‑порт, который будет разрешён firewall‑правилами | `2323` |
| `HY2XS_FIREWALL_MODE` | Режим управления nftables: `managed`, `takeover`, `external`, `off` | `takeover` |
| `HY2XS_FIREWALL_STAGED_APPLY` | Включает staged apply и rollback guard firewall | `true` |
| `HY2XS_UI_BIND_HOST` | IPv4 bind HY2XS admin | `127.0.0.1` |
| `HY2XS_UI_PUBLIC_ACCESS` | Флаг публичного UI‑доступа. В baseline оставляйте `false` | `false` |
| `HY2XS_UI_PORT` | Порт HY2XS admin | `8080` |
| `HY2XS_ADMIN_USER` | Bootstrap‑логин администратора | `hy2xsadmin` |
| `HY2XS_ADMIN_INITIAL_PASSWORD` | Bootstrap‑пароль администратора; `__GENERATE__` генерируется при install | `__GENERATE__` |
| `HY2XS_ADMIN_CON_PASS` | Bootstrap‑секрет peer/auth слоя; `__GENERATE__` генерируется при install | `__GENERATE__` |
| `HY2XS_FORCE_PASSWORD_CHANGE` | Принудительная смена пароля. UX‑flow пока не включён в production baseline | `false` |
| `HY2XS_ALLOW_SELF_SIGNED_DEV` | Разрешает `self_signed_dev` TLS‑режим | `false` |
| `HY2XS_TLS_MODE` | TLS‑режим: `acme`, `file`, `self_signed_dev` | `acme` |
| `HY2XS_ACME_TYPE` | ACME challenge: `http`, `tls`, `dns`; `dns` пока не поддержан production‑профилем | `http` |
| `HY2XS_ACME_EMAIL` | Email для ACME | `admin@withen.pro` |
| `HY2XS_TLS_CERT_PATH` | Путь к cert при `file`/`self_signed_dev` | `/etc/hysteria/server.crt` |
| `HY2XS_TLS_KEY_PATH` | Путь к key при `file`/`self_signed_dev` | `/etc/hysteria/server.key` |
| `HY2XS_HYSTERIA_BIND_HOST` | Bind Hysteria2. В production profile фиксируется на `0.0.0.0` | `0.0.0.0` |
| `HY2XS_HYSTERIA_PORT` | UDP‑порт Hysteria2 | `443` |
| `HY2XS_HYSTERIA_AUTH_MODE` | Auth mode Hysteria2. Фиксированное значение production‑профиля | `http` |
| `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` | Тип обфускации: `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` |
| `HY2XS_HYSTERIA_CONFIG_PATH` | Путь Hysteria2 config. В production baseline фиксирован | `/etc/hysteria/config.yaml` |
| `HY2XS_INSTALL_DIR` | Каталог установки HY2XS admin | `/opt/hy2xs-admin` |
| `HY2XS_DATA_DIR` | Data‑каталог HY2XS admin | `/var/lib/hy2xs-admin` |
| `HY2XS_LOG_DIR` | Log‑каталог HY2XS | `/var/log/hy2xs` |
### Режимы firewall
| Режим | Поведение |
| --- | --- |
| `managed` | HY2XS управляет nftables, но останавливается при обнаружении чужого `/etc/nftables.conf` |
| `takeover` | HY2XS явно берёт управление nftables на себя |
| `external` | HY2XS не меняет nftables; оператор сам отвечает за firewall |
| `off` | Firewall‑слой HY2XS отключён |
При `managed` и `takeover` генерируется nftables‑конфигурация с default drop policy, разрешением loopback, established/related, SSH‑порта, ACME challenge‑порта, Hysteria2 UDP‑порта и ICMP echorequest.
## Реконфигурация
После изменения `/etc/hy2xs/hy2xs.env` сначала выполните dry‑run:
```bash
hy2xs-orchestrator reconfigure \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env \
--dry-run
```
Если ошибок нет, примените изменения:
```bash
hy2xs-orchestrator reconfigure \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env \
--apply
```
`reconfigure --apply` выполняет backup, генерирует конфиги, обновляет systemd‑юниты, применяет firewall, выполняет smoke‑checks и при ошибке пытается откатить изменённое состояние.
Важно: `HY2XS_ADMIN_INITIAL_PASSWORD` и `HY2XS_ADMIN_CON_PASS` являются installonly bootstrap‑полями. Их изменение в `/etc/hy2xs/hy2xs.env` после первичной установки не ротирует уже созданные credentials в SQLite автоматически.
## Команды управления
| Команда | Назначение |
| --- | --- |
| `hy2xs-orchestrator status` | Показать состояние платформы, сервисов, firewall и install marker |
| `hy2xs-orchestrator doctor` | Выполнить preflight и smokechecks текущей установки |
| `hy2xs-orchestrator reconfigure --dry-run` | Проверить конфиг без применения |
| `hy2xs-orchestrator reconfigure --apply` | Применить runtime‑конфигурацию |
| `hy2xs-orchestrator repair` | Попытаться восстановить partial install state |
| `hy2xs-orchestrator diagnostics collect` | Собрать diagnostic bundle в `/var/log/hy2xs/diagnostics` |
| `hy2xs-orchestrator redact-config` | Отредактировать секреты в env/yaml перед публикацией логов |
Пример сбора диагностики:
```bash
hy2xs-orchestrator diagnostics collect \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env
```
## Проверка безопасности после установки
Минимальный набор проверок:
```bash
# SSH слушает только ожидаемый порт
ss -H -ltn | grep -E ':(22|2323) '
# password auth отключён
sshd -T | grep -E '^(port|permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|allowtcpforwarding|permitopen) '
# UI не слушает публичный 0.0.0.0
ss -H -ltn | grep ':8080'
# Hysteria2 слушает UDP-порт
ss -H -lun | grep ':443'
# nftables-конфиг валиден
nft -c -f /etc/nftables.conf
# сервисы активны
systemctl is-active hysteria-server hy2xs-admin
```
Ожидаемые SSH‑значения:
```text
port 2323
permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
allowtcpforwarding local
permitopen 127.0.0.1:8080 localhost:8080
```
## Troubleshooting
### Установка падает на DNS AAAA
Причина: домен имеет IPv6 AAAA‑запись, а HY2XS production profile является IPv4only.
Решения:
1. удалить AAAA‑запись у домена;
2. либо временно установить `HY2XS_DNS_AAAA_POLICY=warn`, если оператор осознанно принимает риск клиентских IPv6‑маршрутов вне текущего baseline.
### Установка падает на проверке SSH‑порта
HY2XS firewall‑слой проверяет, что порт из `HY2XS_SSH_PORT` уже слушается. Если указано `2323`, но `sshd` продолжает слушать только `22`, установка остановится.
Проверьте:
```bash
ss -H -ltn | grep -E ':(22|2323) '
sshd -T | grep '^port '
```
### Вход по паролю всё ещё работает
Проверьте ранние provider‑конфиги:
```bash
grep -RniE '^[[:space:]]*(PermitRootLogin|PasswordAuthentication|KbdInteractiveAuthentication|PubkeyAuthentication)\b' \
/etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf
```
Если есть ранний файл с `PasswordAuthentication yes`, он может применяться раньше вашего hardening‑файла. Закомментируйте конфликтующие директивы и создайте `00-hy2xs-operator.conf`, как показано в quick start.
### UI не открывается в браузере
Проверьте, что SSH‑туннель запущен и сервис слушает localhost:
```bash
systemctl status hy2xs-admin --no-pager
ss -H -ltn | grep ':8080'
curl -sS http://127.0.0.1:8080/healthz
```
На локальной машине проверьте, что порт не занят другим приложением. При необходимости используйте локальный порт `18080` вместо `8080`.
### Нужно отправить логи без секретов
Соберите диагностику:
```bash
hy2xs-orchestrator diagnostics collect \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env
```
Перед публикацией отдельных env/yaml файлов используйте redaction:
```bash
hy2xs-orchestrator redact-config \
--config /etc/hy2xs/hy2xs.env \
--out /root/hy2xs.env.redacted \
--format env
```
## Сборка release‑пакета
Обычному пользователю не нужно собирать проект из исходников. Этот раздел нужен maintainer’у, который готовит release‑архив.
Сборка поддерживается на Debian 13 amd64 из чистого git work tree.
```bash
apt-get update
apt-get install -y git ca-certificates curl unzip tar xz-utils build-essential pkg-config bash coreutils findutils grep sed gawk openssl
git clone <repo-url>
cd <repo-dir>
git status --short
```
Подготовьте build env:
```bash
export PACKAGE_VERSION=1.0.0
export BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ)
# Для переносимости между x86_64-серверами без AVX2 предпочтителен baseline artifact.
export BUN_FLAVOR=x64-baseline
# Builder требует SHA256 для скачиваемых toolchain-архивов.
# Значения нужно брать из официальных release/checksum источников для конкретных версий.
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>
```
Запустите сборку:
```bash
./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
dist/hy2xs-install-<version>.tar.gz
```
Проверьте архив:
```bash
ls -lh dist/hy2xs-install-*.tar.gz
sha256sum dist/hy2xs-install-*.tar.gz
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)$'
```
Подробная документация по сборочному слою находится в [`tools/build/README.md`](tools/build/README.md).
## Структура репозитория
```text
.
├── apps/ # HY2XS admin: Go backend + Vue/Vite frontend
├── 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
```
Каталог `dist/` создаётся builder’ом и не должен храниться в git.
## Для кого этот проект
HY2XS рассчитан на операторов, которым нужен воспроизводимый способ поставить Hysteria2‑сервер с локальной панелью управления, не собирая проект на production‑сервере и не открывая admin UI наружу.
Проект особенно полезен, если важны:
- строгая target‑платформа;
- установка из одного release‑архива;
- локальный UI через SSH‑туннель;
- systemd/nftables baseline;
- проверяемая установка со smoke‑checks;
- понятная диагностика при сбоях.
## Лицензия
HY2XS распространяется на условиях **GNU Affero General Public License v3.0 only** (`AGPL-3.0-only`).
Полный текст лицензии находится в [`LICENSE`](LICENSE).
Сторонние библиотеки и зависимости сохраняют собственные лицензии.
---
<p align="center">Разработано во <a href="https://flamy.studio">Flamy Studio</a>.</p>