Skip to content

Hysteria2 — Xray-core ​

Xray-core поддерживает Hysteria v2, но разбивает конфигурацию на несколько блоков: протокольный settings (версия, адрес/порт, пользователи), транспортный streamSettings.hysteriaSettings (аутентификация, тайм-аут простоя UDP, маскировка) и streamSettings.finalmask для управления перегрузкой, полосы пропускания и скачков портов. Чтобы исходящий был работоспособен, заполнить нужно и settings, и hysteriaSettings.

Исходящий — протокольный уровень ​

settings для исходящего с "protocol": "hysteria":

ПолеТипПо умолчаниюДопустимые значенияОписание
versionint32(required)2Должно быть ровно 2. Любое другое значение отклоняется при запуске (infra/conf/hysteria.go:19-21).
address*Address(required)<host>Имя хоста или IP сервера.
portuint16(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":

ПолеТипПо умолчаниюДопустимые значенияОписание
versionint32(required)2Должно быть 2.
users[]*HysteriaUserConfig[][HysteriaUserConfig]Принимаемые пользователи. users и clients — взаимозаменяемые ключи с одинаковой формой.
clients[]*HysteriaUserConfig[][HysteriaUserConfig]Принимаемые пользователи (альтернативный ключ; та же форма, что у users).

Исходный код: infra/conf/hysteria.go:39-43 · зафиксировано на v26.9.9 (52a412d)

clients[] ​

ПолеТипПо умолчаниюДопустимые значенияОписание
authstring(required)<string>Строка аутентификации.
leveluint320<uint32>Уровень политики для этого пользователя.
emailstring(unset)<string>Метка в статистике / журналах.

Исходный код: infra/conf/hysteria.go:33-37 · зафиксировано на v26.9.9 (52a412d)

Транспортный уровень — hysteriaSettings ​

Задаётся в streamSettings.hysteriaSettings. Содержит аутентификацию, тайм-аут простоя UDP и маскировку входящего; управление перегрузкой, полоса пропускания и скачки портов находятся в finalmask (ниже).

ПолеТипПо умолчаниюДопустимые значенияОписание
versionint32(required)2Версия протокола Hysteria. Должна совпадать с version в settings.
authstring(required on outbound)<string>Строка аутентификации исходящего. На входящем это поле передаётся валидатору, но аутентификация пользователей задаётся в settings.clients[].auth.
udpIdleTimeoutint6460<2..600 seconds>Секунды простоя UDP-потока до закрытия QUIC-потока. Должно быть от 2 до 600 включительно (infra/conf/transport_method.go:764-766).
masqueradeMasquerade(unset)MasqueradeТолько для входящего: маскировка HTTP-ответом для неаутентифицированного трафика.

Исходный код: infra/conf/transport_method.go:752-757 · зафиксировано на v26.9.9 (52a412d)

masquerade ​

ПолеТипПо умолчаниюДопустимые значенияОписание
typestring(required)file | proxy | stringВыбирает, какой под-блок применяется.
dirstring(file only)<dir path>Каталог, отдаваемый при type: file.
urlstring(proxy only)<URL>Вышестоящий URL при type: proxy.
rewriteHostboolfalsetrue | falseПереписывать заголовок Host при проксировании (type: proxy).
xForwardedboolfalsetrue | falseДобавлять заголовки X-Forwarded-For / X-Forwarded-Host / X-Forwarded-Proto к проксируемым запросам (type: proxy).
insecureboolfalsetrue | falseПропустить проверку TLS у вышестоящего при type: proxy.
contentstring(string only)<text>Тело, возвращаемое при type: string.
headersmap[string]string{}{<header>: <value>}Дополнительные заголовки ответа при type: string.
statusCodeint32200<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:

ПолеТипПо умолчаниюДопустимые значенияОписание
congestionstring(empty)brutal | force-brutal | bbr | renoУправление перегрузкой для Hysteria. Пусто / brutal: Brutal на min(brutalUp, объявленная пиром скорость приёма), если обе известны, иначе BBR. force-brutal: всегда Brutal на brutalUp (требует brutalUp). bbr: всегда BBR. reno: обычный Reno.
bbrProfilestringstandardconservative | standard | aggressiveПрофиль настройки BBR; применяется всякий раз, когда выбран BBR. Неизвестные значения вызывают ошибку при сборке конфигурации.
brutalUpBandwidth(unset)<bandwidth>Скорость отправки этой стороны для Brutal в виде строки с единицей (см. «Синтаксис полосы пропускания»). Если задана, должна быть не меньше 65536 байт/с (512 kbps).
brutalDownBandwidth(unset)<bandwidth>Скорость приёма, которую эта сторона объявляет пиру при рукопожатии Hysteria; пир ограничивает ею свою скорость отправки Brutal. Синтаксис и минимум — как у brutalUp.
brutalDisableLossCompensationboolfalsetrue | 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 открывает при каждом скачке.
modestring(required)intervalLocal | intervalRemote | perConnRemote | <comma-separated combination>Что меняется при каждом скачке (без учёта регистра, через запятую). intervalLocal каждый интервал открывает новый локальный UDP-сокет (новый порт источника); intervalRemote каждый интервал выбирает новый порт / IP назначения из remotePorts / remoteIPs; perConnRemote выбирает случайное назначение один раз на соединение. Пустое или неизвестное значение вызывает ошибку при сборке конфигурации. Ответы читаются только из сокетов, открытых скачком intervalLocal, поэтому включайте его (например, "intervalLocal,intervalRemote").
intervalInt32Range(required)<seconds> | "<min>-<max>"Секунды между скачками; диапазон каждый раз даёт случайное значение. Обе границы должны быть не меньше 5 — иначе соединение завершается ошибкой invalid interval при установлении.
remotePortsPortList(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, bps1
k, kb, kbps1024
m, mb, mbps1 048 576
g, gb, gbps1 073 741 824
t, tb, tbps1 099 511 627 776

Числовая часть разбирается как float64, результат делится на 8 (в protobuf передаются байты в секунду, но единица в источнике названа bps).

Примеры ​

Исходящий:

json
{
  "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-маскировкой:

json
{
  "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)

Core Tutorial от Argsment