惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42
美团技术团队
NISL@THU
NISL@THU
C
Cisco Blogs
SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
Cloudbric
Cloudbric
雷峰网
雷峰网
T
Tailwind CSS Blog
博客园 - 司徒正美
The Register - Security
The Register - Security
L
LangChain Blog
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
B
Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Threat Research - Cisco Blogs
I
InfoQ
S
Schneier on Security
L
Lohrmann on Cybersecurity
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
Google DeepMind News
Google DeepMind News
Cisco Talos Blog
Cisco Talos Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
D
Docker
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
H
Hacker News: Front Page
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 聂微东
Webroot Blog
Webroot Blog
MongoDB | Blog
MongoDB | Blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Разделение исходящего и входящего трафика по разным IP-адресам в XRAY
Андрей · 2026-06-24 · via Все публикации подряд на Хабре

Средний

9 мин

761

В наше непростое время... Хотя, к чему все это? Все в курсе. Переходим к технической части.

Многие знают, что XRAY умеет получать запрос от клиента на один ip адрес, а отправлять ответ с другого ip адреса. Документации на этот счет в интернете крайне немного (ну или я не умею искать). Есть образцы базовых настроек в примерах на GitHub проекта XTLS и несколько упоминаний о существовании такой фишки в статьях на Хабре без подробностей реализации. Я же попробую описать здесь теорию и настройку разделения входящего и исходящего трафика подробно и с примерами.

Зачем все это нужно?

  1. Теоретически, это усложняет поведенческий анализ трафика со стороны DPI. Паттерны ломаются и, в теории, это помогает обойти блокировки. Но это не точно.

  2. Если такая фича существует, ее нужно запилить и посмотреть как все это работает на практике. Чисто из научного интереса.

На чем будем настраивать?

На сервере стоит Angie (версия 1.11.6) в качестве реверсивного прокси, за ним прячется панель 3x-ui (версия 3.4.0), которая управляет XRAY (версия 26.6.22). Будем исходить из этой конфигурации.

Можно ли реализовать разделение трафика без реверсивного прокси?

Все упирается в расшифровку двух разных потоков SSL в рамках одного входящего подключения в XRAY. Умеет он такое или нет, я информации не нашел. В настройках подключения есть возможность указать несколько SSL сертификатов, но нет возможности указать несколько SNI, так что возможно, это будет работать только для ip без доменных имен. Скажу честно, я не пробовал.

Важная деталь: у Вашего сервера обязательно должно быть два внешних ip адреса. Желательно из разных подсетей, хотя различие подсетей не играет никакой роли. Большинство хостеров раздает несколько ip на один VDS. У меня эта опция стоит 5 руб в день за каждый дополнительный адрес. Можно делать настройки напрямую с ip адресами, но, для красоты и наглядности, предлагаю к каждому ip привязать свой поддомен. У нас это будут upload.domain.com и download.domain.com. Привязка делается в настройках DNS зоны у регистратора доменов. Интересное наблюдение. Несмотря на то, что оба моих ip адреса на одном и том же VDS, выданы одним и тем же хостером и находятся физически в одном и том же датацентре, 2ip.ru показывает, что один ip адрес расположен в Москве, а второй в Новосибирске, что забавно.

Можно использовать разные VDS для разделения трафика. Физически это могут быть разные машины в разных дата-центрах в разных странах на разных континентах. Для этого нужно с проксировать весь входящий трафик с download сервера на upload сервер с помощью любого реверсивного прокси. На download сервере даже XRAY не нужен. О том как запилить такое проксирование есть ролик на замедленном Youtube на примере Caddy. Но тут есть несколько моментов.

  1. Если оба сервера находятся внутри локальной сети в одном дата-центре, то это ничем не отличается от варианта два ip на одном VDS, а если нет разницы, зачем платить больше?

  2. Если оба сервера находятся в разных дата-центрах, мы получаем дополнительные накладные расходы в виде задержек трафика между серверами без видимой целесообразности, ибо DPI ломается от различия ip адресов, а не от их географического расположения. Опять же, два сервера минимум в два раза дороже, чем один сервер с двумя ip адресами.

Поэтому из экономии будем рассматривать вариант один сервер - два ip.

Итак, погнали. Настраиваем Angie.

Создаем файл xray.conf в папке /etc/angie/http.d. Имя файла может быть любым. Расширение строго conf

xray.conf
server {
    listen x.x.x.1:443 ssl;
    server_name upload.domain.com;

    http2 on;

    ssl_certificate /etc/letsencrypt/live/upload.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/upload.domain.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets on; 

    client_header_timeout 5m;
    keepalive_timeout 5m;

   location /api/v1/data/ {
        client_max_body_size 0;
        
        proxy_pass http://unix:/dev/shm/xrxhd.socket;
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_cache off;
        
        proxy_connect_timeout 60s;
        proxy_read_timeout 315s;
        proxy_send_timeout 5m;
   }
}

server {
    listen x.x.x.2:443 ssl;
    server_name download.domain.com;

    http2 on;

    ssl_certificate /etc/letsencrypt/live/download.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/download.domain.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets on; 

    client_header_timeout 5m;
    keepalive_timeout 5m;

   location /api/v1/data/ {
        client_max_body_size 0;
        
        proxy_pass http://unix:/dev/shm/xrxhd.socket;
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_cache off;
        
        proxy_connect_timeout 60s;
        proxy_read_timeout 315s;
        proxy_send_timeout 5m;
   }
}

Пояснения к настройкам:

  1. Для NGINX настройки аналогичные.

  2. Вместо x.x.x.1 и x.x.x.2 пишем внешние ip адреса вашего сервера. Если вы не привязывали доменные имена, поле server_name опускаете (вообще не пишете).

  3. Сертификаты для доменов или ip адресов предварительно нужно получить самостоятельно у Let's Encript или кого угодно еще.

  4. ssl_ciphers и add_header - не догма, пишите как считаете нужным.

  5. Разделы location должны быть аналогичные для обоих ip адресов, включая путь /api/v1/data/ (любой, но одинаковый. И не забудьте слеш в конце) и файл сокета.

  6. Если не хотите использовать сокет, для общения с XRAY, в proxy_pass можно прописать адрес и порт: 127.0.0.1:4443. Порт может быть любым свободным, он дальше будет использоваться при настройке XRAY.

Создаем входящее подключение для XRAY

Через панель 3x-ui: Входящие - Создать подключение.

Вкладка Основное:

Примечание: все что угодно. Это название подключения.

Протокол: vless

Адрес: /dev/shm/xrxhd.socket,0666. Здесь внимательно. Адрес сокета должен совпадать с адресом сокета в настройках реверсивного прокси. После запятой идут права доступа к файлу сокета, их лучше оставить как в примере. Если в настройках реверс прокси вы указывали 127.0.0.1:4443, то здесь пишем 127.0.0.1

Порт. Если используете сокет, ставите 0 или 1, если 127.0.0.1:4443, ставите 4443 (или какой указали в настройках реверсивного прокси).

Вкладка Поток:

Транспорт - XHTTP.

Путь: /api/v1/data - берем из секции location настроек реверсивного прокси. В этом случае без слеша в конце.

Режим: auto - это важно.

Остальное оставляем как есть.

Вкладка Безопасность: выбираем Нет. За расшифровку SSL у нас отвечает реверсивный прокси.

Вкладка Сниффинг: Включить, выбрать все что есть HTTP, TLS, QUIC, FAKEDNS.

Если выше не упомянуты какие-то поля настроек - оставляем их без изменений.

Дальше добавьте клиента в получившееся входящее подключение (раздел панели Клиенты - Добавить клиентов - Привязанные входящие).

В итоге получаем вот такой шаблон входящего подключения:

{
  "listen": "/dev/shm/xrxhd.socket,0666",
  "port": 1,
  "protocol": "vless",
  "tag": "in-1-tcp",
  "settings": {
    "clients": [
      {
        "id": "xxxxxxxxxxxxxxxx",
        "email": "xxxxx",
        "flow": "",
        "limitIp": 0,
        "totalGB": 0,
        "expiryTime": 0,
        "enable": true,
        "tgId": 0,
        "subId": "xxxxxx",
        "comment": "",
        "reset": 0,
        "created_at": 1756652179000,
        "updated_at": 1782274393000
      }
    ],
    "decryption": "none",
    "encryption": "none"
  },
  "sniffing": {
    "enabled": true,
    "destOverride": [
      "http",
      "tls",
      "quic",
      "fakedns"
    ]
  },
  "streamSettings": {
    "network": "xhttp",
    "xhttpSettings": {
      "path": "/api/v1/data",
      "host": "",
      "mode": "auto",
      "xPaddingBytes": "100-1000",
      "scMaxEachPostBytes": "1000000",
      "scMaxBufferedPosts": 30,
      "scStreamUpServerSecs": "20-80"
    },
    "security": "none"
  }
}

На этом с настройками сервера все. Настройка фаервола, маршрутизации в XRAY и прочие настройки на сервере не относятся к делу, а значит выходят за рамки и без того скучной статьи. ИИ в помощь.

Для чистоты эксперимента проверять делится наш трафик или не делится будем на чистом XRAY без графических клиентов. К сторонним клиентам мы еще вернемся. Как известно, бинарник XRAY одновременно является и клиентом и сервером, поэтому качаем последнюю версию под свою платформу (Windows или Linux роли не играет) прямо с GitHub разработчика. Создаем файл конфигурации для клиента config.json.

Примерно такой
{
  "log": {
    "access": "access.log",
    "error": "error.log",
    "loglevel": "debug",
    "dnsLog": true
  },
  "inbounds": [
    {
      "listen": "127.0.0.1",
      "port": 2080,
      "protocol": "socks",
      "settings": {
        "udp": true
      },
      "tag": "socks-in"
    },
    {
      "listen": "127.0.0.1",
      "port": 2081,
      "protocol": "http",
      "tag": "http-in"
    }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "upload.domain.com",
            "port": 443,
            "users": [
              {
                "id": "xxxxxxxxxxxxx",
                "security": "auto",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "tag": "vless-out",
      "streamSettings": {
        "network": "xhttp",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "upload.domain.com",
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "firefox"
        },
        "xhttpSettings": {
          "path": "/api/v1/data",
          "host": "upload.domain.com",
          "mode": "auto",
          "xPaddingBytes": "100-1000",
          "downloadSettings": {
            "address": "download.domain.com",
            "port": 443,
            "network": "xhttp",
            "security": "tls",
            "tlsSettings": {
              "serverName": "download.domain.com",
              "alpn": [
                "h2",
                "http/1.1"
              ],
              "fingerprint": "firefox"
            },
            "xhttpSettings": {
              "path": "/api/v1/data",
              "host": "download.domain.com",
              "mode": "auto"
            }
          }
        }
      }
    }
  ]
}

Что важно пояснить в конфигурации.

Во всех секциях, вне “downloadSettings” указываем домен upload.domain.com или ip адрес x.x.x.1 из настроек реверсивного прокси на сервере. Внутри “downloadSettings” соответственно download.domain.com или ip адрес x.x.x.2.

“mode”: “auto” - во всех случаях. Можно в разделе “xhttpSettings”: для исходящего домена upload.domain.com поэкспериментировать с “mode”: “stream-up” или “mode”: “packet-up”, но auto работает точно. “mode”: “stream-one” в нашем случае гарантированно работать не будет. Такова жизнь.

“loglevel”: “debug” - важно указать именно debug, так как нам нужно проверить разделение трафика, а не только ошибки.

Получившийся файл config.json кладем рядом с бинарником XRAY и запускаем из командной строки. Не забудьте сначала в командной строке перейти в папку, где лежит XRAY (cd ... и вот это вот все).

xray --config config.json

Дальше идет описание проверки из под Windows.

Заходим в настройки Windows -> Сеть и Интернет -> Прокси-сервер -> Настройка прокси вручную -> Настройка. Использовать прокси-сервер -> Вкл. IP адрес прокси-сервера 127.0.0.1. Порт 2081 берем из настроек файла клиента (раздел с “protocol”: “http”). Сохраняем, запускаем браузер, открываем 2ip.ru видим ip адрес сервера. Ну или не видим, но чаще видим. Если не видим, проверяем, что сделали не так.

Теперь открываем файл error.log. Он должен появиться в той же папке, что и бинарник XRAY. В этом файле важно найти строки:

transport/internet/splithttp: XHTTP is dialing to tcp:upload.domain.com:443, mode packet-up, HTTP version 2, host upload.domain.com
transport/internet/splithttp: XHTTP is downloading from tcp:download.domain.com:443, mode stream-down, HTTP version 2, host download.domain.com

Должны быть обе строки. Могут идти не подряд, но обязательно должны быть обе. Если в логе есть только первая строка (XHTTP is dialing to tcp ...) - ничего не получилось и весь трафик идет через один ip. Идем в начало статьи, смотрим где накосячили с настройками.

Для тех кто в Linux можно проверить работоспособность нашей поделки через curl. XRAY предварительно должен быть запущен в качестве сервиса или в другом терминале. Номер порта берем из настроек файла клиента (раздел с “protocol”: “socks”).

curl --socks5 127.0.0.1:2080 https://google.com

Дальше, по аналогии с Windows, бежим в логи и ищем две заветные строчки.

Как можно проверить еще, ну вот чтобы вообще на 100%? На примере Windows.

Качаем и запускаем TCPView прямо с сайта Microsoft. В это время у нас уже запущен из командной строки XRAY и включен системный прокси в настройках Windows. В интерфейсе TCPView вверху в поле Search пишем xray, чтобы оставить отображение трафика только одного процеса. Открываем или обновляем в браузере любую страницу. В таблице ниже мы должны увидеть три ip адреса: 127.0.0.1, x.x.x.1 и x.x.x.2. Если видим только два: 127.0.0.1 и x.x.x.1, ничего не работает и день прожит зря. Но, надеюсь, это не про нас.

Что касается графических клиентов для XRAY. Финт с разделением потоков удалось провернуть только на клиенте V2RayN под Windows. Пробовал еще Exclave на Андроиде и Passwall2 на openWRT. В двух последних случаях настройки “downloadSettings” игнорировались и все шло в один поток. Во всех клиентах блок “downloadSettings” я добавлял в раздел "Дополнительные параметры XHTTP (Extra)" в настройках подключения. Просто вставлял блок в соответствующее поле:

"downloadSettings": {
            "address": "download.domain.com",
            "port": 443,
            "network": "xhttp",
            "security": "tls",
            "tlsSettings": {
              "serverName": "download.domain.com",
              "alpn": [
                "h2",
                "http/1.1"
              ],
              "fingerprint": "firefox"
            },
            "xhttpSettings": {
              "path": "/api/v1/data",
              "host": "download.domain.com",
              "mode": "auto"
            }
          }

В случае V2RayN это сработало, Exclave и Passwall2 просто проигнорировали эти настройки, хотя само соединение поднималось. Если у кото-то получится разделить трафик на Андроиде или openWRT, будет очень интересно почитать.

В заключении добавлю, что вся информация предоставлена исключительно в образовательных и научных целях. Ни в коем случае не используйте полученные знания для нарушения закона и доступа к богомерзким запрещенным ресурсам в сети интернет. Да прибудет с Вами сила. Всем бобра.