Hysteria2 — Xray-core
Xray-core поддерживает Hysteria v2, но разбивает конфигурацию на несколько блоков: протокольный settings (версия, адрес/порт, пользователи), транспортный streamSettings.hysteriaSettings (аутентификация, тайм-аут простоя UDP, маскировка) и streamSettings.finalmask для управления перегрузкой, полосы пропускания и скачков портов. Чтобы исходящий был работоспособен, заполнить нужно и settings, и hysteriaSettings.
Исходящий — протокольный уровень
settings для исходящего с "protocol": "hysteria":
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
version | int32 | (required) | 2 | Должно быть ровно 2. Любое другое значение отклоняется при запуске (infra/conf/hysteria.go:19-21). |
address | *Address | (required) | <host> | Имя хоста или IP сервера. |
port | uint16 | (required) | <port> | UDP-порт сервера. |
Исходный код: infra/conf/hysteria.go:13-17 · зафиксировано на v26.9.9 (52a412d)
Hysteria v1 не поддерживается
Поле version обязано равняться 2. HysteriaClientConfig.Build (infra/conf/hysteria.go:19-21) возвращает errors.New("version != 2") для любого другого значения.
Входящий — протокольный уровень
settings для входящего с "protocol": "hysteria":
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
version | int32 | (required) | 2 | Должно быть 2. |
users | []*HysteriaUserConfig | [] | [HysteriaUserConfig] | Принимаемые пользователи. users и clients — взаимозаменяемые ключи с одинаковой формой. |
clients | []*HysteriaUserConfig | [] | [HysteriaUserConfig] | Принимаемые пользователи (альтернативный ключ; та же форма, что у users). |
Исходный код: infra/conf/hysteria.go:39-43 · зафиксировано на v26.9.9 (52a412d)
clients[]
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
auth | string | (required) | <string> | Строка аутентификации. |
level | uint32 | 0 | <uint32> | Уровень политики для этого пользователя. |
email | string | (unset) | <string> | Метка в статистике / журналах. |
Исходный код: infra/conf/hysteria.go:33-37 · зафиксировано на v26.9.9 (52a412d)
Транспортный уровень — hysteriaSettings
Задаётся в streamSettings.hysteriaSettings. Содержит аутентификацию, тайм-аут простоя UDP и маскировку входящего; управление перегрузкой, полоса пропускания и скачки портов находятся в finalmask (ниже).
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
version | int32 | (required) | 2 | Версия протокола Hysteria. Должна совпадать с version в settings. |
auth | string | (required on outbound) | <string> | Строка аутентификации исходящего. На входящем это поле передаётся валидатору, но аутентификация пользователей задаётся в settings.clients[].auth. |
udpIdleTimeout | int64 | 60 | <2..600 seconds> | Секунды простоя UDP-потока до закрытия QUIC-потока. Должно быть от 2 до 600 включительно (infra/conf/transport_method.go:764-766). |
masquerade | Masquerade | (unset) | Masquerade | Только для входящего: маскировка HTTP-ответом для неаутентифицированного трафика. |
Исходный код: infra/conf/transport_method.go:752-757 · зафиксировано на v26.9.9 (52a412d)
masquerade
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
type | string | (required) | file | proxy | string | Выбирает, какой под-блок применяется. |
dir | string | (file only) | <dir path> | Каталог, отдаваемый при type: file. |
url | string | (proxy only) | <URL> | Вышестоящий URL при type: proxy. |
rewriteHost | bool | false | true | false | Переписывать заголовок Host при проксировании (type: proxy). |
xForwarded | bool | false | true | false | Добавлять заголовки X-Forwarded-For / X-Forwarded-Host / X-Forwarded-Proto к проксируемым запросам (type: proxy). |
insecure | bool | false | true | false | Пропустить проверку TLS у вышестоящего при type: proxy. |
content | string | (string only) | <text> | Тело, возвращаемое при type: string. |
headers | map[string]string | {} | {<header>: <value>} | Дополнительные заголовки ответа при type: string. |
statusCode | int32 | 200 | <int> | Код статуса, возвращаемый при type: string. |
Исходный код: infra/conf/transport_method.go:737-750 · зафиксировано на v26.9.9 (52a412d)
Поле type переключает активный под-блок: file использует dir, proxy — url/rewriteHost/xForwarded/insecure, string — content/headers/statusCode.
Управление перегрузкой и полоса пропускания — finalmask.quicParams
Задаётся в streamSettings.finalmask.quicParams (блок параметров QUIC, общий с другими транспортами на базе QUIC). Поля, относящиеся к Hysteria:
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
congestion | string | (empty) | brutal | force-brutal | bbr | reno | Управление перегрузкой для Hysteria. Пусто / brutal: Brutal на min(brutalUp, объявленная пиром скорость приёма), если обе известны, иначе BBR. force-brutal: всегда Brutal на brutalUp (требует brutalUp). bbr: всегда BBR. reno: обычный Reno. |
bbrProfile | string | standard | conservative | standard | aggressive | Профиль настройки BBR; применяется всякий раз, когда выбран BBR. Неизвестные значения вызывают ошибку при сборке конфигурации. |
brutalUp | Bandwidth | (unset) | <bandwidth> | Скорость отправки этой стороны для Brutal в виде строки с единицей (см. «Синтаксис полосы пропускания»). Если задана, должна быть не меньше 65536 байт/с (512 kbps). |
brutalDown | Bandwidth | (unset) | <bandwidth> | Скорость приёма, которую эта сторона объявляет пиру при рукопожатии Hysteria; пир ограничивает ею свою скорость отправки Brutal. Синтаксис и минимум — как у brutalUp. |
brutalDisableLossCompensation | bool | false | true | false | Запрещает Brutal повышать скорость отправки для компенсации измеренных потерь пакетов — тогда он отправляет ровно с заданной скоростью. |
Исходный код: infra/conf/transport_finalmask.go:993-1011 · зафиксировано на v26.9.9 (52a412d)
Скачки портов — udphop в finalmask.udp
Скачки портов — это клиентская UDP-маска: добавьте в streamSettings.finalmask.udp элемент с "type": "udphop" и укажите параметры ниже в его settings. Он должен быть первым элементом finalmask.udp и работает только на исходящем — входящий отклоняет его с udphop: client only. Сервер по-прежнему слушает один порт; перенаправьте на него диапазон скачков (например, правилом iptables DNAT / REDIRECT).
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
sockopt | *SocketConfig | (unset) | SocketConfig | Параметры сокета для новых локальных сокетов, которые intervalLocal открывает при каждом скачке. |
mode | string | (required) | intervalLocal | intervalRemote | perConnRemote | <comma-separated combination> | Что меняется при каждом скачке (без учёта регистра, через запятую). intervalLocal каждый интервал открывает новый локальный UDP-сокет (новый порт источника); intervalRemote каждый интервал выбирает новый порт / IP назначения из remotePorts / remoteIPs; perConnRemote выбирает случайное назначение один раз на соединение. Пустое или неизвестное значение вызывает ошибку при сборке конфигурации. Ответы читаются только из сокетов, открытых скачком intervalLocal, поэтому включайте его (например, "intervalLocal,intervalRemote"). |
interval | Int32Range | (required) | <seconds> | "<min>-<max>" | Секунды между скачками; диапазон каждый раз даёт случайное значение. Обе границы должны быть не меньше 5 — иначе соединение завершается ошибкой invalid interval при установлении. |
remotePorts | PortList | (keep original port) | <port / range list> | Порты назначения для скачков, например "20000-50000" или [443, "8000-9000"]. Используются intervalRemote / perConnRemote. |
remoteIPs | []string | (keep original IP) | <IP or CIDR> | … | Адреса назначения для скачков. CIDR выбирает случайный адрес внутри префикса. Используются intervalRemote / perConnRemote. |
Исходный код: infra/conf/transport_finalmask.go:911-917 · зафиксировано на v26.9.9 (52a412d)
Синтаксис полосы пропускания
brutalUp и brutalDown разбираются вспомогательной функцией в infra/conf/transport_method.go:696-735. Принимаемые суффиксы:
| Суффикс | Множитель |
|---|---|
(пусто), b, bps | 1 |
k, kb, kbps | 1024 |
m, mb, mbps | 1 048 576 |
g, gb, gbps | 1 073 741 824 |
t, tb, tbps | 1 099 511 627 776 |
Числовая часть разбирается как float64, результат делится на 8 (в protobuf передаются байты в секунду, но единица в источнике названа bps).
Примеры
Исходящий:
{
"outbounds": [
{
"tag": "hy2-out",
"protocol": "hysteria",
"settings": {
"version": 2,
"address": "example.com",
"port": 443
},
"streamSettings": {
"network": "hysteria",
"security": "tls",
"tlsSettings": { "serverName": "example.com" },
"hysteriaSettings": {
"version": 2,
"auth": "<password>",
"udpIdleTimeout": 120
},
"finalmask": {
"quicParams": {
"brutalUp": "100mbps",
"brutalDown": "300mbps"
},
"udp": [
{
"type": "udphop",
"settings": {
"mode": "intervalLocal,intervalRemote",
"remotePorts": "20000-50000",
"interval": "5-30"
}
}
]
}
}
}
]
}Входящий с двумя пользователями и файловой HTTP-маскировкой:
{
"inbounds": [
{
"tag": "hy2-in",
"listen": "0.0.0.0",
"port": 443,
"protocol": "hysteria",
"settings": {
"version": 2,
"clients": [
{ "auth": "<alice>", "email": "alice" },
{ "auth": "<bob>", "email": "bob" }
]
},
"streamSettings": {
"network": "hysteria",
"security": "tls",
"tlsSettings": { "certificates": [{ "certificateFile": "/etc/ssl/cert.pem", "keyFile": "/etc/ssl/key.pem" }] },
"hysteriaSettings": {
"version": 2,
"masquerade": {
"type": "file",
"dir": "/var/www"
}
}
}
}
]
}Примечания
- Частая ошибка: задать
authтолько внутриsettings(как если бы это было поле имени пользователя/пароля). Xray читает аутентификацию исходящего изstreamSettings.hysteriaSettings.auth. Пользователи входящего задаются вsettings.clients[].auth(для каждого пользователя), а транспортныйauthпри сопоставлении игнорируется. congestion,up,downиudphopне являются полямиhysteriaSettings. Xray не отклоняет неизвестные ключи, поэтому указанные там значения молча игнорируются. Задавайте их черезfinalmask.quicParams.congestion/brutalUp/brutalDownи элементudphopвfinalmask.udp.- Xray-core реализует только Hysteria 2:
versionдолжно быть равно2, любое другое значение означает жёсткий отказ. udpIdleTimeout < 2или> 600вызывает ошибку при запуске (infra/conf/transport_method.go:764-766).
Сравнение с другими ядрами
- sing-box использует единый, гораздо более плоский блок — без транспортного разделения. Полоса задаётся простым
intв Мбит/с (без строки с единицей), а маскировка поддерживает полиморфную форму (строка-URL или типизированный объект). См. Hysteria2 — sing-box. - mihomo тоже одноблочный; скачки портов задаются через
ports(синтаксис диапазонов) плюсhop-interval. mihomo принимает строки с суффиксами единиц дляup/down, какbrutalUp/brutalDownв Xray. См. Hysteria2 — mihomo.
Исходный код: infra/conf/hysteria.go:13-43 · v26.9.9 (52a412d)
