Skip to content

Instantly share code, notes, and snippets.

@rz6agx
Last active October 19, 2025 17:38
Show Gist options
  • Select an option

  • Save rz6agx/45f04bd501c87b0e282b7cdbf0dd5808 to your computer and use it in GitHub Desktop.

Select an option

Save rz6agx/45f04bd501c87b0e282b7cdbf0dd5808 to your computer and use it in GitHub Desktop.
Малоизвестные фичи XRay

Малоизвестные фичи XRay

В этом посте я кратко поведаю о разных интересных возможностях XRay (клиент и сервер для протоколов VMess, VLESS, Trojan и других, в том числе с XTLS-Reality и XTLS-Vision), о которых, кажется, мало кто знает, но которые могут оказаться очень полезными.

Fragment

На фоне недавних событий (замедление Youtube Роскомнадзором), многие открыли для себя инструменты типа GoodbyeDPI и подобных. Они работают с использованием различных трюков при передаче данных по протоколу TCP, благодаря которым цензурирующее оборудование (так называемое ТСПУ) при обработке TLS-handshake оказывается сбитым с толку и не понимает, на какой именно сайт вы пытаетесь попасть (потому что не может прочитать параметр "SNI" при установке TLS-соединения), и в итоге блокировка/замедление не срабатывает. XRay тоже умеет подобное, там это называется "Fragment".

Простейший конфиг XRay для этого будет выглядеть примерно так:

{
  "inbounds": [
    {
      "listen": "127.0.0.1",
      "port": 1080,
      "protocol": "socks",
      "tag": "socks"
    }
  ],
  "outbounds": [
    {
      "tag": "fragment",
      "protocol": "freedom",
      "settings": {
        "fragment": {
          "packets": "tlshello",
          "length": "100-200",
          "interval": "10-20"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true
        }
      }
    }
  ]
}

Запустив XRay с таким конфигом и настроив браузер на использование SOCKS-прокси на локальном (127.0.0.1) порту 1080, XRay будет фрагментировать заголовок ClientHello протокола TLS. Доступные параметры:

  • packets: может быть "1-3" для фрагментации на уровне TCP (первые 1-3 отправки данных от клиента к серверу) либо "tlshello" для фрагментации TLS handshake;
  • length: на кусочки какого размера дробить отправляемые данные;
  • interval: пауза между отправкой фрагментов в миллисекундах;

Конкретные требуемые значения параметров могут отличаться в зависимости от типа (и даже версии софта) используемого оборудования DPI у провайдера, поэтому возможно чтобы получить нужный эффект придется с ними поэкспериментировать. Fragment можно также комбинировать с использованием прокси-протоколов, например VLESS и других, пример конфига есть на github.

QUIC-транспорт

Еще из того, о чем недавно говорили на фоне замедления Youtube - протокол QUIC. Это разработка Google, которая использует UDP вместо TCP при доступе к веб-серверам, нацеленная на уменьшение времени установки соединения и улучшение скорости доступа за счет более эффективной передачи данных. В случае с замедлением Youtube у некоторых пользователей включение QUIC в браузере помогло решить проблему (а у некоторых наоборот, выключение). Причин тут может быть несколько. Во-первых, есть основание предполагать, что определенное оборудование ТСПУ... не умеет нормально разбирать заголовки QUIC-протокола (и из-за этого одно время Роскомнадзор даже резал такие подключения). Во-вторых, в браузере Chrome разработчики намеренно добавили фрагментацию данных при установке соединения - они таким образом пытались заставить разработчиков веб-серверов полностью следовать стандарту протокола, и эта фрагментации дала очень полезный побочный эффект для обхода цензуры (см. предыдущую часть статьи). В третьих, QUIC очень эффективно работает при потерях пакетов, а оборудование РКН замедляет Youtube именно таким образом.

И XRay умеет использовать QUIC в качестве транспорта для своих протоколов (VLESS, VMess, Trojan и другие). Вы можете спросить, зачем использовать QUIC-транспорт, когда можно использовать VLESS безо всяких транспортов (поверх обычного TLS), отвечу - всегда полезно иметь запасной альтернативный вариант, к тому же QUIC в XRay можно использовать по-разному.

Вариант раз - в чистом виде. С QUIC, к сожалению, не получится сделать что-то типа XTLS-Reality, когда вы прикрываетесь чужим доменом. В теории это возможно, но пока что никто такое не реализовал. Поэтому понадобится свой домен и TLS-сертификат для него (подойдет даже бесплатный домен от dynu.com и сертификат от LetsEncrypt). Конфиг XRay для примера:

{
  "inbounds": [
    {
      "port": 443,
      "protocol": "vless",
      "tag": "quic",
      "settings": {
        "clients": [
          {
            "id": "4c3fe585-bb09-89df-b284-e2dada14150f",
            "email": "user1"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "quic",
        "quicSettings": {},
        "security": "tls",
        "tlsSettings": {
          "certificates": [
          {
            "certificateFile": "/etc/letsencrypt/live/yourdomain/fullchain.pem",
            "keyFile": "/etc/letsencrypt/live/yourdomain/privkey.pem"
          }]
        }
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "quic",
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "block"
    }
  ]
}

Потом в клиенте настраиваете VLESS-подключение с нужным UUID, вводите адрес (домен) вашего сервера, выбираете QUIC в качестве транспорта - и все работает. Такое подключение будет со стороны выглядеть как настоящий QUIC на 443 UDP порту, но, к сожалению, настроить fallback (чтобы при заходе на UDP/443 открывался фейковый веб-сайт) в XRay возможности нет.

Второй вариант - использовать обфусцированный QUIC. Домен и сертификат для этого уже не нужны (их все равно никто не увидит). Со стороны передача данных будет выглядеть как "нечто непонятное по UDP", примерно как в случае с AmneziaWG.

{
  "log": {
    "loglevel": "debug"
  },
  "inbounds": [
    {
      "port": 8443,
      "protocol": "vless",
      "tag": "quic",
      "settings": {
        "clients": [
          {
            "id": "4c3fe585-bb09-89df-b284-e2dada14150f",
            "email": "user1"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "quic",
        "quicSettings": {
           "security": "aes-128-gcm",
           "key": "hellohabr"
        }
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "quic",
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "block"
    }
  ]
}

В данном случае используется шифр aes-128-gcm с ключом hellohabr. Клиенты настраиваются аналогично предыдущему случаю, только надо отключить TLS, а вместо этого выбрать шифр и ключ.

И еще один вариант, близкий ко второму - замаскировать QUIC под DTLS (WebRTC, звонки в месседжерах), SRTP (FaceTime) или uTP (BitTorrent). Для этого нужно добавить параметр header:

      "streamSettings": {
        "network": "quic",
        "quicSettings": {
           "security": "aes-128-gcm",
           "key": "hellohabr",
           "header": {
             "type": "dtls"
           }
        }

Где параметр "type" может быть "srtp", "utp", "dtls", "wechat-video" и "wireguard". Не забудьте на клиенте выбрать то же самое.

Транспорт QUIC в XRay работает стабильно и обладает всеми возможностями обфускации. Недостатка два. Первый, как я уже сказал, когда вы маскируетесь под "чистый" QUIC, нельзя добавить маскировочный сайт. Второй - вся эта красота работает только с клиентами на базе XRay-core, а те что на базе Sing-box в пролете (точнее, sing-box не поддерживает обфусцированный QUIC, чистый в теории должен работать, но не заработал). Если вам нужен прокси поверх QUIC с маскировкой под сайт или под "непонятно что" и работающий с Sing-box, используйте Hysteria2.

Selectors и observatory - мониторинг и автоматический выбор outbound'а

Некоторые используют XRay для построения цепочек прокси. Например, вы находясь в России подключаетесь сначала к прокси-серверу находящемуся в России, а уже с него куда-нибудь за бугор. XRay позволяет контролировать доступность вышестоящих прокси-серверов (если у вас их несколько) и балансировать запросы между ними. Фичи называются selectors и observatory. Документация здесь.

Расскажу про конфиг вкратце. На верхнем уровне вашего конфига добавляете объект observatory:

  "observatory": {
    "subjectSelector": [ "outbound1", "outbound2" ],
    "probeURL": "http://www.gstatic.com/generate_204",
    "probeInterval": "300s",
    "enableConcurrency": true
  },

В списке subjectSelector перечисляете имена outbound'ов которые надо проверять, в probeURL задаете адрес для теста, в probeInterval периодичность. А потом в объекте routing описываете объект balancers, например так:

  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "balancers": [
      {
        "tag": "mybalancer",
        "selector": [ "outbound1", "outbound2" ],
        "strategy": {
          "type": "leastPing"
        },
        "fallbackTag": "outbound3"
      },

В selector перечисляете outbound'ы, через которые можно подключаться "наружу", в fallbackTag можно указать outbound который XRay попытается использовать если все перечисленные выше окажутся недоступные (и он же будет использоваться сразу после старта пока еще не прошли проверки). И дальше вы можете использовать ваш mybalancer как обычный outbound - например указать его явно в правилах роутинга.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment