fix(admin): закрыть обещания панели, которые продукт не выполнял
Девятый проход, по итогам приёмки v1.0.0-rc1 на живом Debian 13. Общая тема:
интерфейс обещал оператору то, что продукт умел, но до чего не доходило
управление.
Секрет пира. Подпись под полем предлагала оставить его пустым, сервер умел его
сгенерировать, и генерация была недостижима: в go-playground/validator тег
omitempty НЕ пропускает правило, если поле объявлено указателем и указатель не
nil — hasValue считает указатель на пустую строку «значением». Правило min=6
применялось к пустой строке и отказывало. Ловушка закрыта общим шагом
нормализации DTO, а не тегом на одном поле: та же ловушка ломала фильтр списка
пиров, где очищенный крестиком el-input отправляет `?name=`. Граница проходит по
каждому полю отдельно — у remark пустая строка означает «убрать пометку», у
disabled ноль означает «включён».
Отказы. Любая ошибка любого поля превращалась в слово `invalid`, а слой vo
определял код ответа СРАВНЕНИЕМ текста сообщения — тот же антипаттерн, который
запрещён панели, только на сервере. Ответ несёт errors[{code, field, message,
params}]; панель выбирает фразу по коду и подставляет причины под поля.
Сессия. Ветка «войдите заново» была недостижима дважды: сервер отвечает HTTP 200
на любой отказ, поэтому обработчик ошибок axios не вызывался, а условие в нём
проверяло code === "A0230" и поле msg, которых в этом API никогда не было.
Истёкший токен вдобавок уезжал с кодом системной ошибки.
Иконки. Контракт currentColor был объявлен в двух местах и не действовал: восемь
ассетов несли литеральный fill="#000000" на <path>, а атрибут представления
перебивает унаследованное CSS-свойство. Под это попадали все семь иконок
бокового меню на фоне #181818.
Имя пира. Два правила на одном поле противоречили друг другу (min=1 против
6-32), а копия набора символов в слое контроллеров несла неэкранированный дефис
и впускала `, - . / : ; <` — через панель проходило имя peer/name, которое
импорт того же пира отклонял. Набор символов ЛОГИНА сознательно не сужен и
закреплён тестом: он приходит из HY2XS_ADMIN_USER и оркестратором не
ограничивается.
Добавлены подпись «Разработано во Flamy» с адресом, принадлежащим приложению, и
контрактные тесты панели как обязательный шаг сборки. Их исполняет Bun, а не
vitest: jsdom не вычисляет currentColor и визуальной корректности не доказал бы,
зато vitest привёл бы в граф pnpm audit сотню транзитивных зависимостей.
docs/ разложена по слоям, 11-testing-and-acceptance.md (117 КБ) разбит на пять
частей, добавлен docs/acceptance/ с отчётом о прогоне rc1 и перечнем дефектов.
Обход документации в приёмке стал рекурсивным: плоский docs/*.md после
разнесения по каталогам совпадал бы ровно с одним файлом.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# Architecture baseline
|
||||
|
||||
## Цель
|
||||
|
||||
Зафиксировать одну непротиворечивую схему без смешивания локальной сборки, серверной установки и внешнего access layer.
|
||||
|
||||
## Два слоя системы
|
||||
|
||||
### 1. Builder layer
|
||||
Запускается **только локально**, на отдельной машине разработчика / оператора.
|
||||
|
||||
Функции:
|
||||
- хранение исходников проекта
|
||||
- хранение и сопровождение исходного кода **HY2XS admin**
|
||||
- хранение исходников оркестратора на **Bun + TypeScript**
|
||||
- компиляция install-артефакта оркестратора
|
||||
- подготовка install package
|
||||
- упаковка unit-файлов, шаблонов конфигов и документации
|
||||
- контроль версии проекта как целого
|
||||
|
||||
Builder layer **не разворачивается на сервере**.
|
||||
|
||||
### 2. Runtime / target layer
|
||||
Запускается **только на чистом Debian 13**.
|
||||
|
||||
Функции:
|
||||
- установка системных зависимостей
|
||||
- разворачивание файлов пакета
|
||||
- скачивание **свежей Hysteria2 из официального upstream**
|
||||
- создание server config
|
||||
- установка и запуск **встроенного HY2XS admin**
|
||||
- создание systemd unit-файлов
|
||||
- применение nftables baseline
|
||||
- создание `post-install.env`
|
||||
|
||||
Target layer **не содержит сборщика** и **не выполняет target-side build**.
|
||||
|
||||
## Компоненты baseline
|
||||
|
||||
### Серверный транспорт
|
||||
- **Hysteria2**
|
||||
- QUIC/UDP
|
||||
- один фиксированный UDP-порт
|
||||
- `Gecko` включён по умолчанию, `Salamander` доступен как режим совместимости
|
||||
- IPv4-only
|
||||
- лимит по умолчанию: 50/50 Mbps на клиента
|
||||
- fallback congestion controller: BBR (профиль `standard`)
|
||||
|
||||
### UI слой
|
||||
- **HY2XS admin** — штатный компонент проекта
|
||||
- поставляется внутри проекта
|
||||
- устанавливается локально из итогового пакета
|
||||
- не скачивается с upstream на сервере
|
||||
|
||||
### Orchestrator слой
|
||||
- **Bun + TypeScript**
|
||||
- собирается локально builder layer'ом
|
||||
- попадает на target как готовый install-артефакт
|
||||
- не требует `npm/pnpm/yarn/bun install` на сервере
|
||||
|
||||
### Server ops слой
|
||||
- systemd
|
||||
- nftables
|
||||
- `post-install.env`
|
||||
|
||||
## Принципы
|
||||
|
||||
### 1. Ядро, UI и оркестратор ведут себя по-разному
|
||||
- Hysteria2: последнюю стабильную upstream-версию выбирает **сборка пакета**, установка ставит уже замороженный артефакт
|
||||
- HY2XS admin: разрабатываем **внутри проекта** и поставляем его сами
|
||||
- Оркестратор: пишем на **Bun + TypeScript**, но собираем **локально**, а не на target
|
||||
|
||||
### 2. Builder и target не смешиваются
|
||||
Сборка — локально.
|
||||
Установка — на сервере.
|
||||
На сервере не должно быть логики «собери мне UI» или «собери мне TypeScript оркестратор».
|
||||
|
||||
### 3. Оркестратор install/reconfigure-only
|
||||
Оркестратор умеет только:
|
||||
- установить
|
||||
- применить явную реконфигурацию из runtime env
|
||||
- разложить файлы
|
||||
- создать базовую конфигурацию
|
||||
- подготовить сервер к работе
|
||||
|
||||
Он **не** умеет:
|
||||
- обновлять уже установленную систему
|
||||
- откатывать версии
|
||||
- удалять установку
|
||||
- чинить неизвестные поломанные старые состояния
|
||||
|
||||
### 4. Access layer вынесен за рамки baseline
|
||||
Telegram-бот, backend выдачи ключей, remote profile publishing, billing и похожие пользовательские контуры не входят в этот baseline.
|
||||
|
||||
## Что входит в baseline
|
||||
|
||||
1. local builder
|
||||
2. install package
|
||||
3. vanilla Hysteria2 from upstream
|
||||
4. bundled HY2XS admin
|
||||
5. Bun/TypeScript install-only orchestrator
|
||||
6. systemd + nftables
|
||||
7. post-install env
|
||||
8. install-only flow под чистый Debian 13
|
||||
|
||||
## Что не входит в baseline
|
||||
|
||||
- target-side builder
|
||||
- target-side git clone нашего UI
|
||||
- target-side `bun install` / transpile / compile
|
||||
- Telegram-бот
|
||||
- backend выдачи remote profiles
|
||||
- standalone update / rollback / uninstall subcommands
|
||||
|
||||
При этом в install/reconfigure допускается bounded rollback для failure-сценариев firewall/systemd/config/smoke.
|
||||
- Docker как основной способ поставки
|
||||
- multi-node deployment
|
||||
- сложный control plane
|
||||
|
||||
## Финальный результат
|
||||
|
||||
Правильный baseline-результат выглядит так:
|
||||
|
||||
1. На локальной машине собирается install package.
|
||||
2. В пакет уже встроены наш HY2XS admin и install-артефакт оркестратора.
|
||||
3. Пакет переносится на чистый Debian 13.
|
||||
4. На сервере запускается только install-only orchestration.
|
||||
5. Сервер скачивает свежую Hysteria2 из official upstream.
|
||||
6. Сервер разворачивает bundled UI из пакета.
|
||||
7. Создаются systemd unit-файлы, firewall baseline и `post-install.env`.
|
||||
8. Сервер готов как базовое рабочее окружение HY2XS.
|
||||
|
||||
## Runtime policy
|
||||
|
||||
- editable слой: `/etc/hy2xs/hy2xs.env` (0600)
|
||||
- snapshot слой: `/etc/hysteria/post-install.env` (0600)
|
||||
- изменения runtime применяются только через явный `reconfigure --dry-run/--apply`
|
||||
- IPv6 out of scope: все bind/listen только IPv4
|
||||
@@ -0,0 +1,248 @@
|
||||
# Server Hysteria2 baseline
|
||||
|
||||
## Цель документа
|
||||
|
||||
Зафиксировать правила для серверного слоя Hysteria2 в модели, где UI поставляется вместе с проектом, а Hysteria берётся из official upstream во время установки.
|
||||
|
||||
## Роль Hysteria2
|
||||
|
||||
Hysteria2 — основной транспортный компонент сервера.
|
||||
Он не вендорится и не собирается как часть HY2XS.
|
||||
|
||||
## Source policy
|
||||
|
||||
Базовое правило:
|
||||
- Hysteria2 скачивается **во время установки**
|
||||
- источник — **официальный upstream**
|
||||
- install layer не должен подменять собой upstream-дистрибуцию Hysteria2
|
||||
|
||||
## Версионная политика
|
||||
|
||||
Ключевое правило: **«последняя стабильная» определяется на этапе сборки пакета, а не на целевом сервере.**
|
||||
|
||||
Не «HY2XS использует Hysteria vX.Y.Z», а:
|
||||
|
||||
> HY2XS по умолчанию берёт последний стабильный релиз Hysteria, доступный на момент сборки пакета. Разрешённая версия, URL артефакта и контрольная сумма замораживаются в получившемся install package.
|
||||
|
||||
Практика:
|
||||
|
||||
- builder обращается к каноническому upstream `HyNetworks/hysteria`;
|
||||
- принимаются только стабильные релизы с тегом вида `app/vX.Y.Z`, без draft и prerelease;
|
||||
- берётся ровно один артефакт `hysteria-linux-amd64`, URL используется в том виде, в каком его отдал upstream API;
|
||||
- SHA-256 считается локально от скачанного артефакта, а не берётся из стороннего файла;
|
||||
- версия, URL и SHA-256 фиксируются в metadata install package;
|
||||
- на target-сервере **никогда** не используется moving `latest`;
|
||||
- бинарник Hysteria2 устанавливается только на этапе `install`;
|
||||
- фактически установленная версия записывается в `post-install.env`;
|
||||
- `reconfigure` не обновляет и не откатывает бинарник Hysteria2.
|
||||
|
||||
Следствие: если между сборкой пакета и его установкой выйдет новая версия Hysteria, содержимое установки **не изменится под ногами**. Повторная установка старого пакета поставит ту же версию, что и в день сборки.
|
||||
|
||||
Переопределения builder:
|
||||
|
||||
```bash
|
||||
HYSTERIA_CHANNEL=stable # по умолчанию: разрешить последнюю стабильную
|
||||
HYSTERIA_CHANNEL=pinned # взять закоммиченный tools/build/hysteria-lock.env, без сети
|
||||
HYSTERIA_VERSION_OVERRIDE=v2.12.2 # закрепить конкретную версию
|
||||
```
|
||||
|
||||
## Compatibility gate
|
||||
|
||||
Автоматический выбор «последней стабильной» без проверки опасен: upstream может изменить схему конфигурации, и builder молча соберёт неработающий HY2XS.
|
||||
|
||||
Поэтому до создания release-пакета builder:
|
||||
|
||||
1. скачивает артефакт и сверяет SHA-256;
|
||||
2. сверяет `hysteria version` с разрешённой версией;
|
||||
3. рендерит канонический конфиг HY2XS **тем же кодом**, который работает на target-сервере;
|
||||
4. запускает реальный бинарник Hysteria с этим конфигом — отдельно для Gecko и для Salamander;
|
||||
5. только после этого формирует пакет.
|
||||
|
||||
Если upstream несовместим, ломается **сборка**:
|
||||
|
||||
```text
|
||||
BUILD FAILED: unsupported Hysteria stable v2.13.0
|
||||
```
|
||||
|
||||
а не production-сервер оператора.
|
||||
|
||||
## Платформа
|
||||
|
||||
- ОС: только Debian 13
|
||||
- init/system management: systemd
|
||||
- сетевой фильтр: nftables
|
||||
- архитектура baseline: x86_64/amd64
|
||||
|
||||
## Listen и сеть
|
||||
|
||||
### Listen
|
||||
- только IPv4
|
||||
- формат: `0.0.0.0:<PORT>`
|
||||
|
||||
### Порт
|
||||
- один фиксированный UDP-порт
|
||||
- этот порт должен совпадать в:
|
||||
- server config
|
||||
- firewall rules
|
||||
- `post-install.env`
|
||||
|
||||
## Обфускация
|
||||
|
||||
Новые установки HY2XS используют **Gecko**.
|
||||
|
||||
Gecko помечен upstream как **experimental**. Он достраивается поверх Salamander: помимо scramble он дополнительно фрагментирует QUIC handshake на пакеты случайного размера. HY2XS использует upstream-defaults размеров пакетов `512/1200` как проверенный production-профиль.
|
||||
|
||||
**Salamander остаётся полностью поддержанным режимом совместимости.** Смена типа обфускации требует соответствующих изменений на клиенте: это изменение wire-совместимости, а не косметическая настройка.
|
||||
|
||||
Baseline:
|
||||
|
||||
```yaml
|
||||
obfs:
|
||||
type: gecko
|
||||
gecko:
|
||||
password: "<сгенерированный пароль>"
|
||||
minPacketSize: 512
|
||||
maxPacketSize: 1200
|
||||
```
|
||||
|
||||
Режим совместимости:
|
||||
|
||||
```yaml
|
||||
obfs:
|
||||
type: salamander
|
||||
salamander:
|
||||
password: "<сгенерированный пароль>"
|
||||
```
|
||||
|
||||
Правила:
|
||||
- тип выбирается через `HY2XS_HYSTERIA_OBFS_TYPE` (`gecko` | `salamander`);
|
||||
- пароль должен быть сильным, генерируется автоматически при `__GENERATE__` или пустом значении;
|
||||
- пароль фиксируется в конфигурационном контуре и доступен оператору через runtime config и `post-install.env`;
|
||||
- `obfs`-блок формируется оркестратором целиком, а не собирается из отдельных placeholders внутри YAML — комбинация вида `type: gecko` рядом с блоком `salamander` структурно невозможна.
|
||||
|
||||
### Почему размеры пакетов Gecko не вынесены в env
|
||||
|
||||
Официальная схема `hysteria2://` передаёт только тип обфускации и пароль. `minPacketSize` и `maxPacketSize` в ссылку не помещаются.
|
||||
|
||||
Если разрешить оператору произвольные значения, сгенерированная клиентская ссылка перестанет полностью описывать подключение и потребуется отдельный формат — выгружаемый клиентский профиль. Пока такой задачи нет, фиксация `512/1200` даёт корректную ссылку и воспроизводимое поведение.
|
||||
|
||||
Валидация (на случай будущего расширения) централизована в оркестраторе: `min > 0`, `max >= min`, `max <= 2048`.
|
||||
|
||||
## Версия схемы конфигурации
|
||||
|
||||
```bash
|
||||
HY2XS_CONFIG_SCHEMA_VERSION=2
|
||||
```
|
||||
|
||||
Пакет понимает только свою версию схемы. Конфигурация с другой версией отклоняется fail-fast, а не применяется частично.
|
||||
|
||||
HY2XS `v1` **не мигрирует установки `0.x` на месте**: между `0.x` и `1.0.0` изменились схема конфигурации, тип обфускации по умолчанию и контракт выбора версии Hysteria. Переход выполняется чистой установкой.
|
||||
|
||||
## TLS
|
||||
|
||||
Требования:
|
||||
- production default: `acme`
|
||||
- поддерживаемые режимы: `acme | file | self_signed_dev`
|
||||
- `self_signed_dev` только для dev/lab и только при явном `HY2XS_ALLOW_SELF_SIGNED_DEV=true`
|
||||
- корректный `server_name` / SNI на клиентах
|
||||
- одна понятная TLS policy
|
||||
- без смешивания нескольких несовместимых схем по умолчанию
|
||||
|
||||
Инварианты:
|
||||
- `acme` -> только `acme` block в конфиге;
|
||||
- `acme` block обязан содержать `type: http|tls` из runtime env (`HY2XS_ACME_TYPE`);
|
||||
- `HY2XS_ACME_TYPE=dns` в production-профиле запрещён до отдельной реализации;
|
||||
- `HY2XS_HYSTERIA_AUTH_MODE` зафиксирован в `http` и валидируется fail-fast;
|
||||
- `HY2XS_HYSTERIA_OBFS_TYPE` принимает `gecko` (default) или `salamander` и валидируется fail-fast;
|
||||
- блок `masquerade` в baseline не задаётся: при включённой обфускации сервер и так перестаёт быть обычным HTTP/3 endpoint, поэтому masquerade не даёт выигрыша, а `404 Not Found` на обычный HTTP-трафик — ожидаемое поведение;
|
||||
- `ech` в baseline не включается: при включённой обфускации соединение целиком перестаёт выглядеть как обычный QUIC, поэтому ECH не даёт дополнительной выгоды (он полезен в bare-режиме);
|
||||
- `file` -> только `tls.cert`/`tls.key` block;
|
||||
- `self_signed_dev` -> только dev сценарии.
|
||||
|
||||
## Auth policy
|
||||
|
||||
Для baseline выбирается одна предсказуемая auth-модель.
|
||||
|
||||
Правила:
|
||||
- install flow должен оставить рабочий auth state
|
||||
- bootstrap auth material должен быть либо передан оператором, либо безопасно сгенерирован
|
||||
- дальнейшая модель выдачи доступа пользователям не фиксируется в этом пакете docs
|
||||
|
||||
## Bandwidth и congestion
|
||||
|
||||
Серверная baseline policy:
|
||||
- `bandwidth.up = 50 mbps`
|
||||
- `bandwidth.down = 50 mbps`
|
||||
- `bandwidth.disableLossCompensation = false`
|
||||
- `ignoreClientBandwidth = false`
|
||||
- `congestion.type = bbr`
|
||||
- `congestion.bbrProfile = standard`
|
||||
|
||||
Важно:
|
||||
- эти параметры сами по себе не исчерпывают speed policy;
|
||||
- корректный лимит ожидается только в паре с совместимым клиентским конфигом;
|
||||
- `congestion` — это **fallback** controller: он применяется, когда Brutal bandwidth не согласован сторонами. Подробнее — в [06-speed-limits-and-congestion.md](06-speed-limits-and-congestion.md).
|
||||
|
||||
## QUIC stateless reset
|
||||
|
||||
```yaml
|
||||
quic:
|
||||
disableStatelessReset: false
|
||||
```
|
||||
|
||||
Начиная с Hysteria 2.12.1 сервер отправляет stateless reset, чтобы клиент со stale-соединением после перезапуска сервера или сна устройства переподключался сразу, а не по таймауту. В 2.12.2 появилась возможность это отключить.
|
||||
|
||||
Для VPN-подобного применения HY2XS быстрый reconnect — плюс, поэтому механизм остаётся включённым, а значение фиксируется в конфиге явно.
|
||||
|
||||
## Возможности вне default-профиля
|
||||
|
||||
HY2XS обязан **понимать** современную схему Hysteria, но не обязан включать всё подряд. Разделяются три уровня:
|
||||
|
||||
| Возможность | Генерирует HY2XS | Читает и сохраняет | Отдельный профиль |
|
||||
| --- | :-: | :-: | :-: |
|
||||
| Gecko | да | да | — |
|
||||
| Salamander | fallback | да | — |
|
||||
| BBR / bbrProfile | да | да | — |
|
||||
| Loss compensation | да | да | — |
|
||||
| QUIC stateless reset | да | да | — |
|
||||
| ECH | нет | да | позже |
|
||||
| Mimic | нет | да | позже |
|
||||
| Realms | нет | да | позже |
|
||||
| Port hopping | нет | да | позже |
|
||||
| ACME DNS | нет | да | позже |
|
||||
| Masquerade | нет | да | позже |
|
||||
|
||||
Причина не в качестве этих возможностей, а в том, что каждая меняет соседнюю подсистему:
|
||||
|
||||
- **Mimic** — привилегии, eBPF/XDP, сторонний бинарник, требования к клиенту; текущий systemd-контракт намеренно запускает Hysteria под непривилегированным пользователем с `CapabilityBoundingSet=CAP_NET_BIND_SERVICE`, поэтому Mimic несовместим с ним по построению и требует отдельного security-профиля;
|
||||
- **Realms** — сетевая топология (STUN/hole punching вместо публичного IPv4 и own nftables);
|
||||
- **Port hopping** — nftables и capabilities; официально несовместим с Mimic;
|
||||
- **ECH** — жизненный цикл ключей и распространение конфигурации клиентам (Hysteria не генерирует ECH keypair сама);
|
||||
- **ACME DNS** — учётные данные провайдера и работа с секретами;
|
||||
- **Masquerade** — дополнительное web/proxy-поведение.
|
||||
|
||||
Ни одна из них не должна включаться toggle'ом, который незаметно меняет systemd capabilities или топологию firewall.
|
||||
|
||||
## Рекомендуемые пути
|
||||
|
||||
- `/etc/hysteria/config.yaml`
|
||||
- `/var/lib/hysteria/`
|
||||
- `/etc/hy2xs/hy2xs.env`
|
||||
- `/etc/hysteria/post-install.env`
|
||||
|
||||
## Серверные инварианты
|
||||
|
||||
После установки должно быть верно:
|
||||
|
||||
1. Hysteria2 получена из official upstream по замороженному в пакете URL и SHA-256
|
||||
2. фактическая версия совпадает с версией из metadata пакета и отражена в `post-install.env`
|
||||
3. конфиг валиден
|
||||
4. сервис стартует через systemd
|
||||
5. нужный UDP-порт реально слушается
|
||||
6. тестовый совместимый клиент может подключиться
|
||||
7. bundled UI работает поверх актуального состояния сервера
|
||||
8. `trafficStats.secret` отдельный от `JWT_SECRET`
|
||||
9. IPv6 listen не используется
|
||||
10. публичные клиентские endpoint/URL берутся из `HY2XS_PUBLIC_HOST` + `HY2XS_PUBLIC_PORT`, а не из `listen`/request-host
|
||||
11. сгенерированная `hysteria2://` ссылка содержит фактический тип обфускации и пароль, и совместимый клиент подключается по ней напрямую
|
||||
12. SNI в ссылке берётся из ACME-домена, затем из `HY2XS_DOMAIN`, затем из `HY2XS_PUBLIC_HOST`; IP-адрес как SNI не используется
|
||||
@@ -0,0 +1,60 @@
|
||||
# Client and access scope
|
||||
|
||||
## Цель документа
|
||||
|
||||
Зафиксировать, что клиентский delivery/access layer не является частью install baseline.
|
||||
|
||||
## Что входит в baseline
|
||||
|
||||
В baseline этого пакета docs входит только следующее:
|
||||
- установка Hysteria2
|
||||
- установка HY2XS admin
|
||||
- базовая настройка systemd / firewall / `hy2xs.env` / `post-install.env`
|
||||
- подготовка рабочего серверного окружения
|
||||
|
||||
## Что не входит в baseline
|
||||
|
||||
В baseline **не входят**:
|
||||
- Telegram-бот
|
||||
- backend выдачи профилей
|
||||
- remote profile publishing
|
||||
- deep links
|
||||
- billing / подписки / тарифные планы
|
||||
- отдельный user-access API
|
||||
|
||||
## Что допускается как вспомогательный слой
|
||||
|
||||
Для smoke/manual testing могут существовать:
|
||||
- тестовый клиентский конфиг
|
||||
- тестовый URI
|
||||
- отдельные примеры импортируемых клиентских артефактов
|
||||
|
||||
Но это не делает access layer частью install baseline.
|
||||
|
||||
## Публичный endpoint
|
||||
|
||||
В клиентской части используется только `public_host/public_port`.
|
||||
|
||||
В runtime-обозначениях HY2XS это эквивалентно:
|
||||
- `HY2XS_PUBLIC_HOST`
|
||||
- `HY2XS_PUBLIC_PORT`
|
||||
|
||||
Инварианты:
|
||||
- `listen` и `public endpoint` разделены;
|
||||
- в клиентских URL не используется `0.0.0.0`;
|
||||
- проект остаётся IPv4-only.
|
||||
- если у домена есть AAAA, HY2XS его не обслуживает (IPv6 out of scope).
|
||||
|
||||
## Почему это важно
|
||||
|
||||
Если смешать install baseline и delivery layer, документация начинает неверно обещать лишнее:
|
||||
- будто оркестратор обязан выдавать ключи пользователям
|
||||
- будто сервер после установки автоматически включает пользовательский backend
|
||||
- будто Telegram-бот является обязательной частью системы
|
||||
|
||||
Это неверно.
|
||||
|
||||
## Правильная формулировка
|
||||
|
||||
После выполнения install flow система должна быть готова как серверное окружение HY2XS.
|
||||
Как именно оператор потом выдаёт доступ клиентам — отдельный продуктовый контур и отдельная документация.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Speed limits and congestion policy
|
||||
|
||||
## Цель документа
|
||||
|
||||
Зафиксировать корректную speed policy без неточных упрощений.
|
||||
|
||||
## Что нельзя считать правильной схемой
|
||||
|
||||
Нельзя описывать baseline так:
|
||||
- на сервере включили host BBR
|
||||
- выдали какой-то URI
|
||||
- автоматически получили строгий лимит 50 Mbps на клиента
|
||||
|
||||
Это неверная модель.
|
||||
|
||||
## Три разные вещи, которые нельзя смешивать
|
||||
|
||||
Это главный источник путаницы в теме скоростей Hysteria.
|
||||
|
||||
| Механизм | Что это | Где задаётся |
|
||||
| --- | --- | --- |
|
||||
| **Политика HY2XS 50/50** | продуктовое решение проекта, сколько давать клиенту | `HY2XS_HYSTERIA_BANDWIDTH_UP` / `_DOWN` |
|
||||
| **Brutal bandwidth** | режим Hysteria, работающий по согласованным сторонами значениям полосы | `bandwidth.up` / `bandwidth.down` на сервере + hints на клиенте |
|
||||
| **Fallback congestion controller** | что делает Hysteria, когда Brutal не применяется | `congestion.type` / `congestion.bbrProfile` |
|
||||
|
||||
`50 mbps` здесь — **не** «оптимальная скорость Hysteria» и не свойство протокола. Это политика HY2XS.
|
||||
|
||||
## Что зафиксировано в baseline
|
||||
|
||||
### На сервере
|
||||
- `bandwidth.up = 50 mbps`
|
||||
- `bandwidth.down = 50 mbps`
|
||||
- `bandwidth.disableLossCompensation = false`
|
||||
- `ignoreClientBandwidth = false`
|
||||
- `congestion.type = bbr`
|
||||
- `congestion.bbrProfile = standard`
|
||||
|
||||
### На клиенте
|
||||
Совместимый клиентский конфиг должен задавать соответствующие bandwidth hints:
|
||||
- `up_mbps = 50`
|
||||
- `down_mbps = 50`
|
||||
|
||||
## Практический смысл
|
||||
|
||||
Ожидаемый 50/50 Mbps contract считается корректным только тогда, когда сервер и клиентская конфигурация согласованы.
|
||||
|
||||
Логика выбора внутри Hysteria:
|
||||
|
||||
- когда стороны согласовали Brutal bandwidth — используется Brutal;
|
||||
- когда это не применяется — используется выбранный fallback congestion controller.
|
||||
|
||||
Поэтому BBR тоже является частью явного baseline HY2XS, а не «настройкой по умолчанию, о которой можно не думать».
|
||||
|
||||
## Loss compensation
|
||||
|
||||
```yaml
|
||||
bandwidth:
|
||||
disableLossCompensation: false
|
||||
```
|
||||
|
||||
Компенсация потерь (появилась в Hysteria 2.10.0) позволяет отправлять быстрее заданной полосы, чтобы компенсировать потерю пакетов. В baseline HY2XS она **включена**, а значение фиксируется в конфиге явно — проект про воспроизводимое поведение, а не про молчаливое следование upstream-дефолтам.
|
||||
|
||||
## Что делать с host-level BBR
|
||||
|
||||
`net.ipv4.tcp_congestion_control=bbr` можно оставить как общий системный тюнинг, но:
|
||||
|
||||
- это не главный механизм speed policy Hysteria2;
|
||||
- это не замена клиентским bandwidth hints;
|
||||
- это **не то же самое**, что `congestion.type: bbr` в конфиге Hysteria — у Hysteria собственный congestion-control контур поверх QUIC;
|
||||
- это не центр документации по лимитам.
|
||||
|
||||
## Что фиксировать в `post-install.env`
|
||||
|
||||
Минимум:
|
||||
- `HY2_BANDWIDTH_UP`
|
||||
- `HY2_BANDWIDTH_DOWN`
|
||||
- `HY2_IGNORE_CLIENT_BANDWIDTH`
|
||||
- `HY2_DISABLE_LOSS_COMPENSATION`
|
||||
- `HY2_CONGESTION_TYPE`
|
||||
- `HY2_BBR_PROFILE`
|
||||
|
||||
Дополнительно фиксируется `HY2_VERSION` как фактически установленная версия Hysteria2 и `HY2_RESOLUTION` как способ её выбора при сборке пакета.
|
||||
|
||||
## Что нельзя писать в проектных доках
|
||||
|
||||
Не писать:
|
||||
- «лимит задаётся только на сервере, клиент не важен»
|
||||
- «любой URI достаточно для полной speed policy»
|
||||
- «host BBR и есть логика Hysteria»
|
||||
- «50 mbps — оптимальная скорость Hysteria» (это политика HY2XS, а не свойство протокола)
|
||||
- «Brutal и congestion controller — одно и то же»
|
||||
|
||||
## Правильная baseline-формулировка
|
||||
|
||||
Пер-клиентный лимит 50/50 Mbps обеспечивается согласованной серверной и клиентской конфигурацией. Install baseline отвечает за серверную часть этого контракта; конкретный delivery/access слой в этот документ не входит.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Access layer out of scope
|
||||
|
||||
## Цель документа
|
||||
|
||||
Явно зафиксировать, что пользовательский access/delivery слой не является частью этого baseline-пакета.
|
||||
|
||||
## Что не надо обещать в этих доках
|
||||
|
||||
Нельзя описывать систему так, будто install-only оркестратор также отвечает за:
|
||||
- Telegram-бота
|
||||
- выдачу ключей пользователям
|
||||
- backend профилей
|
||||
- remote profile publishing
|
||||
- deep link delivery
|
||||
- billing или управление подписками
|
||||
|
||||
Это отдельные контуры.
|
||||
|
||||
## Что реально делает baseline
|
||||
|
||||
Baseline делает только следующее:
|
||||
- устанавливает Hysteria2
|
||||
- устанавливает HY2XS admin
|
||||
- создаёт runtime-конфиги
|
||||
- создаёт systemd units
|
||||
- применяет firewall baseline
|
||||
- фиксирует deploy facts в `post-install.env`
|
||||
- применяет runtime изменения только через `reconfigure --dry-run/--apply`
|
||||
|
||||
## Что может существовать рядом, но отдельно
|
||||
|
||||
Отдельно от install baseline могут существовать:
|
||||
- клиентские инструкции
|
||||
- тестовые конфиги
|
||||
- access backend
|
||||
- бот/панель/CRM/ERP-логика выдачи доступа
|
||||
|
||||
Но это требует отдельной документации и отдельного scope.
|
||||
|
||||
## Итоговая формулировка
|
||||
|
||||
HY2XS baseline в этих документах — это **оркестратор установки и базовой серверной конфигурации**, а не пользовательский delivery platform.
|
||||
|
||||
Дополнение: baseline не включает port hopping и не включает updater-логику в HY2XS admin.
|
||||
Reference in New Issue
Block a user