Сквозная миграция 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 файлов), документация на русском.
16 KiB
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:
HYSTERIA_CHANNEL=stable # по умолчанию: разрешить последнюю стабильную
HYSTERIA_CHANNEL=pinned # взять закоммиченный tools/build/hysteria-lock.env, без сети
HYSTERIA_VERSION_OVERRIDE=v2.12.2 # закрепить конкретную версию
Compatibility gate
Автоматический выбор «последней стабильной» без проверки опасен: upstream может изменить схему конфигурации, и builder молча соберёт неработающий HY2XS.
Поэтому до создания release-пакета builder:
- скачивает артефакт и сверяет SHA-256;
- сверяет
hysteria versionс разрешённой версией; - рендерит канонический конфиг HY2XS тем же кодом, который работает на target-сервере;
- запускает реальный бинарник Hysteria с этим конфигом — отдельно для Gecko и для Salamander;
- только после этого формирует пакет.
Если upstream несовместим, ломается сборка:
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:
obfs:
type: gecko
gecko:
password: "<сгенерированный пароль>"
minPacketSize: 512
maxPacketSize: 1200
Режим совместимости:
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.
Версия схемы конфигурации
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-> толькоacmeblock в конфиге;acmeblock обязан содержать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.keyblock;self_signed_dev-> только dev сценарии.
Auth policy
Для baseline выбирается одна предсказуемая auth-модель.
Правила:
- install flow должен оставить рабочий auth state
- bootstrap auth material должен быть либо передан оператором, либо безопасно сгенерирован
- дальнейшая модель выдачи доступа пользователям не фиксируется в этом пакете docs
Bandwidth и congestion
Серверная baseline policy:
bandwidth.up = 50 mbpsbandwidth.down = 50 mbpsbandwidth.disableLossCompensation = falseignoreClientBandwidth = falsecongestion.type = bbrcongestion.bbrProfile = standard
Важно:
- эти параметры сами по себе не исчерпывают speed policy;
- корректный лимит ожидается только в паре с совместимым клиентским конфигом;
congestion— это fallback controller: он применяется, когда Brutal bandwidth не согласован сторонами. Подробнее — в 06-speed-limits-and-congestion.md.
QUIC stateless reset
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
Серверные инварианты
После установки должно быть верно:
- Hysteria2 получена из official upstream по замороженному в пакете URL и SHA-256
- фактическая версия совпадает с версией из metadata пакета и отражена в
post-install.env - конфиг валиден
- сервис стартует через systemd
- нужный UDP-порт реально слушается
- тестовый совместимый клиент может подключиться
- bundled UI работает поверх актуального состояния сервера
trafficStats.secretотдельный отJWT_SECRET- IPv6 listen не используется
- публичные клиентские endpoint/URL берутся из
HY2XS_PUBLIC_HOST+HY2XS_PUBLIC_PORT, а не изlisten/request-host - сгенерированная
hysteria2://ссылка содержит фактический тип обфускации и пароль, и совместимый клиент подключается по ней напрямую - SNI в ссылке берётся из ACME-домена, затем из
HY2XS_DOMAIN, затем изHY2XS_PUBLIC_HOST; IP-адрес как SNI не используется