Update VLESS Reverse Proxy Again

https://github.com/XTLS/Xray-core/pull/6110#issuecomment-4467638188
This commit is contained in:
Meow
2026-05-17 06:52:35 +08:00
parent d89dfc96f4
commit d1b09ea017
3 changed files with 774 additions and 57 deletions
+258 -19
View File
@@ -1,9 +1,10 @@
# Примеры обратного проксирования VLESS
В этой статье показано, как использовать возможность обратного проксирования VLESS в Xray, чтобы через публичный сервер возвращать трафик в удаленную внутреннюю сеть. Ниже рассмотрены два распространенных сценария:
В этой статье показано, как использовать возможность обратного проксирования VLESS в Xray, чтобы через публичный сервер возвращать трафик в удаленную внутреннюю сеть или даже продолжать выход во внешний интернет через домашний широкополосный канал. Ниже рассмотрены три распространенных сценария:
- `Проброс входа`: удаленный проброс порта, то есть сопоставление публичного входного порта с Web-сервисом в удаленной внутренней сети;
- `Удаленно домой`: удаленный роуминг по внутренней сети, когда пользователь проходит через публичный сервер и затем продолжает доступ к ресурсам домашней сети.
- `Удаленно домой`: удаленный роуминг по внутренней сети, когда пользователь проходит через публичный сервер и затем продолжает доступ к ресурсам домашней сети;
- `Выход через домашний канал`: пользователь проходит через публичный сервер, отправляет выбранный трафик обратно на домашнее устройство, а затем выходит во внешний интернет через домашний широкополосный канал.
## Проброс Входа
@@ -212,13 +213,12 @@ sequenceDiagram
### Описание Сценария
Здесь речь не о том, чтобы открыть какой-то публичный порт для внешнего доступа. Вместо этого пользователь сначала подключается к VLESS на публичном сервере, а затем с помощью уже установленного обратного туннеля его трафик отправляется обратно на домашнее внутреннее устройство для дальнейшей обработки.
Здесь речь не о том, чтобы открыть какой-то публичный порт для внешнего доступа. Вместо этого пользователь сначала подключается к публичному Xray-серверу, а затем с помощью уже установленного обратного туннеля его трафик отправляется обратно на домашнее внутреннее устройство для дальнейшей обработки.
Этот вариант ближе к следующим сценариям:
- Доступ к ресурсам домашней локальной сети во время поездок;
- Возврат исходящего трафика конкретного пользователя домой;
- Переход через публичный сервер с последующим доступом к NAS, панели роутера, домашнему DNS или другим внутренним сервисам.
- Переход через публичный сервер с последующим доступом к NAS, панели роутера или другим внутренним сервисам.
```mermaid
flowchart LR
@@ -228,7 +228,7 @@ flowchart LR
H[Ресурсы домашней локальной сети]
I -- Самостоятельно устанавливает обратное VLESS-соединение --> S
U -- Подключается к VLESS inbound на публичном сервере --> S
U -- Подключается к входу Xray на публичном сервере --> S
S -- Пользовательский трафик пересылается через reverse --> I
I -- Повторно обращается к домашней локальной сети --> H
```
@@ -238,9 +238,9 @@ flowchart LR
По сравнению с первой частью, главное отличие здесь не в самой обратной связи, а в цели маршрутизации на публичной стороне:
- В первой части используется `inboundTag -> reverse-out`, чтобы сопоставить определенный входной порт с внутренней сетью;
- Во второй части используется `user -> reverse-out`, чтобы передать проксируемый трафик конкретного пользователя внутреннему устройству для дальнейшей обработки.
- В этой части используется `user -> reverse-out`, чтобы передать проксируемый трафик конкретного пользователя внутреннему устройству для дальнейшей обработки.
Иными словами, здесь публичный сервер больше похож на транзитный узел. Пользователь не "обращается напрямую к сервису, проброшенному через публичный порт", а "сначала подключается к VLESS inbound на публичном сервере, а затем продолжает путь через домашнее устройство".
Иными словами, здесь публичный сервер больше похож на транзитный узел. Пользователь не "обращается напрямую к сервису, проброшенному через публичный порт", а "сначала подключается к входу Xray на публичном сервере, а затем продолжает путь через домашнее устройство".
### Конфигурация Публичного Сервера
@@ -407,7 +407,7 @@ sequenceDiagram
U->>S: Подключается с использованием roam@example.com
S->>S: user-маршрут попадает в reverse-out
S->>I: Отправляет пользовательский трафик в reverse-туннель
I->>H: Обращается к NAS / роутеру / домашнему DNS / внутренним сервисам
I->>H: Обращается к NAS / роутеру / внутренним сервисам
H-->>I: Возвращает ответ
I-->>S: Возвращает через обратный туннель
S-->>U: Отвечает пользователю
@@ -416,36 +416,271 @@ sequenceDiagram
### Чем Этот Вариант Отличается От Первого
- Первый вариант - это "сопоставить один публичный входной порт с фиксированным сервисом в удаленной внутренней сети"; без дополнительной аутентификации такой сервис может быть доступен любому пользователю из интернета.
- Второй вариант - это "дать конкретному пользователю сначала подключиться к публичному Xray-серверу, а затем через обратный прокси вернуться домой и продолжить доступ";
- Эта часть - это "дать конкретному пользователю сначала подключиться к публичному Xray-серверу, а затем через обратный прокси вернуться домой и продолжить доступ";
- Первый вариант больше похож на удаленный проброс порта, то есть на проникновение во внутреннюю сеть;
- Второй вариант больше похож на удаленный роуминг или легкую межплощадочную сеть.
- Эта часть больше похожа на удаленный роуминг или легкую межплощадочную сеть.
### Рекомендации По Безопасности
- Если у вас несколько роуминговых пользователей, рекомендуется выдавать каждому отдельный UUID или отдельный идентификатор;
- В примере ради упрощения используется только VLESS-enc. В реальной эксплуатации могут понадобиться REALITY, XHTTP или другие способы маскировки трафика.
::: tip Расширение
Если вам нужен не режим "доступа к нескольким фиксированным внутренним ресурсам" в формате point-to-site, а межсайтовая L4-сеть, это можно сочетать с таблицами маршрутизации и TUN, либо использовать Xray как шлюз для прозрачного проксирования.
:::
## Выход Через Домашний Канал
Отправить выбранный трафик обратно на домашнее устройство, а затем продолжить выход во внешний интернет через домашний широкополосный канал.
### Описание Сценария
Эта часть не про доступ к домашнему NAS, панели роутера или другим внутренним сервисам. Вместо этого пользователь сначала подключается к публичному Xray-серверу, затем по уже установленному обратному туннелю часть трафика отправляется обратно на домашнее устройство, а уже оттуда продолжается выход во внешний интернет через домашний широкополосный канал.
Этот вариант ближе к следующим сценариям:
- Когда нужно, чтобы выбранный трафик выходил с IP домашнего широкополосного подключения;
- Когда дома нет выделенного публичного IP, нет возможности сделать IPv4-проброс порта, открыть IPv6 firewall или просто не хочется выставлять порт наружу и возиться с DDNS;
- Когда публичный сервер сначала принимает пользователей, а затем отправляет обратно домой только тот трафик, которому нужен домашний выход.
::: tip
Один из конкретных сценариев - использовать домашний широкополосный выход, чтобы ChatGPT не становился "глупее". В отличие от разблокировки стримингов, здесь нужен действительно выделенный резидентский выход. На практике поставщиком такого "настоящего домашнего канала" часто оказывается ваш друг, а перенастраивать его ONT или роутер крайне неудобно. Поэтому самый простой вариант - дать ему устройство, которому достаточно доступа в интернет, и запустить на нем Xray. VLESS reverse proxy очень хорошо ложится на такой сценарий.
Если смотреть шире, даже телефон вашего очень терпеливого друга может работать 7 x 24 как устройство выхода. Для сотовой сети эффект тот же. Здесь уже проверяется дружба.
:::
```mermaid
flowchart LR
U[Внешнее устройство пользователя]
S[Публичный сервер]
I[Домашнее устройство]
P[Публичная цель]
I -- Самостоятельно устанавливает обратное VLESS-соединение --> S
U -- Подключается к входу Xray на публичном сервере --> S
S -- Выбранный трафик пересылается через reverse --> I
I -- Выходит во внешний интернет через домашний канал --> P
```
### Идея Конфигурации
Почти все то же самое, что и во второй части. Меняется только то, на что именно смотрит маршрутизация. Во второй части используется `user -> reverse-out`, а здесь - `определенные домены -> reverse-out`. Сам механизм обратного соединения между публичным сервером и домашним устройством не меняется.
### Конфигурация Публичного Сервера
В этом примере:
- Первый UUID по-прежнему используется домашним устройством для установления обратного соединения;
- Второй UUID используется внешним пользователем для подключения к публичному серверу;
- Маршрутизация отправляет трафик к `geosite:openai` в `reverse-out`.
Сторона публичного сервера почти совпадает со второй частью. Разница только в том, что теперь маршрутизация идет по `domain`, а не по `user`.
```json
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 8443,
"protocol": "vless",
// Здесь рекомендуется включить sniffing, иначе доменное правило может не увидеть целевой домен
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
},
"settings": {
"decryption": "mlkem768x25519plus.native.600s.aCF82eKiK6g0DIbv0_nsjbHC4RyKCc9NRjl-X9lyi0k",
"clients": [
{
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-out"
}
},
{
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision"
}
]
}
}
],
"routing": {
"rules": [
{
"domain": ["geosite:openai"],
"outboundTag": "reverse-out"
}
]
},
"outbounds": [
{
"protocol": "freedom"
}
]
}
```
Смысл этих правил:
- Домашнее устройство возвращается на публичный сервер с первым UUID;
- Внешний пользователь подключается к публичному серверу со вторым UUID;
- Для этого публичного inbound рекомендуется включить `sniffing`, иначе доменное правило может не увидеть целевой домен;
- Любой запрос, попавший под `geosite:openai`, отправляется в `reverse-out`;
- Остальной трафик, не попавший под правило, идет через `freedom` по умолчанию, то есть остается на локальном выходе публичного сервера.
### Конфигурация Домашнего Устройства
Домашняя сторона тоже почти совпадает со второй частью. На этот раз она больше не ограничивается одной внутренней подсетью, а разрешает все адреса, кроме приватных, чтобы трафик мог дальше выходить во внешний интернет через домашний канал.
```json
{
"routing": {
"rules": [
{
"inboundTag": ["reverse-in"],
"outboundTag": "home-direct"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "home-direct",
"settings": {
"finalRules": [
{
"action": "allow",
"network": "tcp,udp",
"ip": ["!geoip:private"]
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-in"
}
}
}
]
}
```
Смысл этих правил:
- Любой трафик, входящий из `reverse-in`, передается в `home-direct`;
- `home-direct` через `finalRules` разрешает только трафик во внешний интернет.
### Конфигурация Устройства Пользователя
На стороне пользователя достаточно классической схемы "`cn -> direct`, все остальное через прокси":
```json
{
"routing": {
"rules": [
{
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"ip": ["geoip:private", "geoip:cn"],
"outboundTag": "direct"
}
]
},
"outbounds": [
{
"protocol": "vless",
"tag": "to-server",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision"
}
},
{
"protocol": "freedom",
"tag": "direct"
}
]
}
```
Смысл этих правил:
- Доменные имена и IP внутри Китая продолжают идти напрямую из локальной сети;
- Остальной трафик, не попавший под правила, по умолчанию идет через `to-server`, то есть отправляется на публичный сервер;
- Уже на публичном сервере правило `geosite:openai -> reverse-out` из предыдущего раздела решает, какой трафик нужно пустить через домашний канал.
### Поток Запроса
```mermaid
sequenceDiagram
participant U as Внешнее устройство пользователя
participant S as Публичный сервер
participant I as Домашнее устройство
participant P as Публичная цель
I->>S: Устанавливает обратное VLESS-соединение
U->>S: Подключается к публичному серверу
U->>S: Отправляет трафик, которому нужен домашний выход
S->>S: Маршрут попадает в reverse-out
S->>I: Отправляет выбранный трафик в reverse-туннель
I->>P: Выходит во внешний интернет через домашний канал
P-->>I: Возвращает ответ
I-->>S: Возвращает через обратный туннель
S-->>U: Отвечает пользователю
```
### Чем Этот Вариант Отличается От Второй Части
- Во второй части цель - "вернуться домой и получить доступ к внутренним ресурсам";
- В этой части цель - "вернуться домой и воспользоваться домашним каналом для выхода во внешний интернет";
- Во второй части основная логика маршрутизации - "каких пользователей нужно вернуть домой";
- В этой части основная логика маршрутизации - "какие домены должны идти через домашний канал".
## Итоги
Обратный прокси VLESS как минимум покрывает два типа сценариев:
К этому моменту статья охватывает три основных сценария и одну производную возможность для обратного прокси VLESS:
- Сопоставление публичного входного порта с фиксированным сервисом в удаленной внутренней сети;
- Подключение пользователя к публичному серверу с последующим возвратом домой через обратный туннель.
- Удаленный проброс порта: сопоставление публичного входного порта с конкретным сервисом в удаленной внутренней сети;
- Point-to-site VPN: подключение пользователя к публичному серверу с последующим возвратом домой через обратный туннель;
- Site-to-site VPN: использование того же механизма как строительного блока для L4-сети между площадками;
- Выход через домашний канал: возврат выбранного трафика домой через публичный сервер с последующим выходом во внешний интернет через домашний широкополосный канал.
Оба сценария используют один и тот же механизм обратного соединения. Основное различие состоит в том, как публичная сторона маршрутизирует трафик и как внутренняя сторона продолжает его обрабатывать. Поняв это, можно свободно расширять схему между "пробросом порта" и "удаленным возвращением домой" под свои задачи.
Во всех случаях используется один и тот же механизм обратного соединения. Основное различие состоит в том, как публичная сторона маршрутизирует трафик и как внутренняя сторона продолжает его обрабатывать. Эта статья только перечисляет несколько типовых схем; гораздо важнее понять сам механизм. Когда принцип станет понятен, его можно дальше расширять под свои задачи.
## Продвинутые Приемы: Расширенная Балансировка Нагрузки
Если у вас есть несколько входов, несколько выходов или обратные соединения из разных регионов, и вы хотите, чтобы группа линий обратного прокси автоматически переживала отказы и распределяла трафик, можно заставить несколько соединений использовать один и тот же `reverse.tag`, то есть объединить их в единый пул доступности.
Если на публичной стороне несколько входящих подключений используют один и тот же reverse tag, в итоге все равно будет создан только один outbound. Это можно понимать как несколько линий, подвешенных к одному общему пулу доступности, где при каждом использовании случайно выбирается одна из живых линий.
Такой подход позволяет строить более гибкие конфигурации many-to-many. Если какая-то линия временно недоступна, например потому что соответствующее внутреннее устройство еще не подключилось, она просто не попадет в текущий пул доступности. Последующий трафик будет автоматически перенаправляться на другие линии, которые все еще в сети, без ручного переключения.
Если какая-то линия временно недоступна, например потому что соответствующее внутреннее устройство еще не подключилось, она просто не попадет в текущий пул доступности. Последующий трафик будет автоматически перенаправляться на другие линии, которые все еще в сети, без ручного переключения.
Иначе говоря, у `reverse.tag` с обеих сторон одна и та же семантика: "одинаковый tag объединяется в один пул соединений":
Та же логика именования разрешена и на внутренней стороне: несколько VLESS outbound тоже могут использовать один и тот же `reverse-in`.
Иначе говоря, `reverse.tag` допускает одинаковые имена на обеих сторонах, и одинаковые теги будут объединяться:
- Несколько клиентов на публичной стороне, использующих один и тот же `reverse-out`, сходятся в один пул outbound;
- Несколько VLESS outbound на внутренней стороне, использующих один и тот же `reverse-in`, сходятся в один пул inbound.
Поэтому схема естественно масштабируется до N-к-N. Более типичный реальный сценарий выглядит так: снаружи есть только один сервисный домен, например `www.example.com`, а GeoDNS отправляет посетителей на ближайший публичный сервер в Лос-Анджелесе или Токио. На внутренней стороне при этом устанавливаются соединения назад к `us-reverse.example.com` и `jp-reverse.example.com`. Затем разворачиваются два внутренних устройства: дома и в офисе. И дом, и офис подключаются и к Лос-Анджелесу, и к Токио, поэтому каждый публичный узел поддерживает пул доступности вида "дом + офис". При реальной переадресации случайно выбирается одна доступная линия из уже установленных соединений. Если одна из точек уходит офлайн, она автоматически исчезает из пула.
Поэтому схема естественно масштабируется до N-к-N. Более типичный реальный сценарий выглядит так: снаружи есть только один сервисный домен, например `www.example.com`, а GeoDNS отправляет посетителей на ближайший публичный сервер в Лос-Анджелесе или Токио. На внутренней стороне при этом устанавливаются соединения назад к `us-reverse.example.com` и `jp-reverse.example.com`. Затем разворачиваются два внутренних устройства: дома и в офисе, и оба подключаются и к Лос-Анджелесу, и к Токио. Каждый публичный узел тогда поддерживает пул доступности вида "дом + офис". При реальной переадресации случайно выбирается одна доступная линия из уже установленных соединений. Если одна из точек уходит офлайн, она автоматически исчезает из пула.
Ниже приведен минимальный фрагмент, в котором оставлены только части, связанные с reverse, и по-прежнему используется модель "публичный входной порт отображается на внутренний сервис".
@@ -558,6 +793,10 @@ sequenceDiagram
Полностью аналогично домашнему внутреннему устройству, только UUID меняются на `us-office-uuid` и `jp-office-uuid`, а `redirect` нужно заменить на тот внутренний сервис, который должен публиковаться из офиса.
::: tip Расширение
Если вы хотите, чтобы выбор здесь был не просто "случайно взять одну из доступных линий", а зависел от задержки, стабильности или результатов наблюдений, это можно дополнительно сочетать с [`routing.balancer`](../../config/routing.md#balancerobject) и спроектировать более тонкую политику выбора outbound.
:::
## Продвинутые Приемы: Передача Реального IP Посетителя
Если вы хотите, чтобы внутренний Web-сервис видел реальный IP посетителя, а не определял источник как IP машины с Xray на внутренней стороне, можно включить `proxyProtocol` у outbound `freedom` на внутренней стороне. Если он выключен, backend Web-сервер обычно видит адрес самой внутренней машины с Xray. Если он включен, Xray перед пересылкой соединения на backend, указанный в `redirect`, сначала отправляет заголовок PROXY protocol, чтобы вместе с ним передать Web-серверу и реальный исходный адрес.
@@ -731,4 +970,4 @@ server {
- Внутренний outbound `freedom`, который принимает трафик обратного прокси, то есть привычный `direct`, желательно настраивать по принципу минимально необходимых привилегий. Сделайте outbound по умолчанию равным `blackhole`, явно маршрутизируйте только разрешенные цели в выделенный `freedom`, а затем через `finalRules` открывайте только действительно нужные адреса и порты.
- Если вы используете сервис проникновения, предоставленный кем-то другим, для удаленного доступа домой, или если вы не полностью доверяете публичному VPS, лучше не направлять трафик обратного прокси напрямую на реальные внутренние сервисы. Вместо этого можно развернуть на внутренней стороне еще один сервер с включенным `VLESS Encryption`, специально для приема такого трафика, и уже через него пересылать трафик к настоящему сервису. Это добавляет аутентификацию и защиту данных; иначе любой, кто имеет достаточный доступ к публичному серверу, потенциально сможет перемещаться по вашей внутренней сети.
- Когда трафик доставляется на внутреннюю сторону через входящие протоколы вроде `VLESS`, протокол, который routing system показывает у `Source` или `Local`, не обязательно совпадает с итоговым `Target`. При использовании условий вроде `source`, `local` или `network` ориентируйтесь на реальную форму трафика, а не на предположение, что они эквивалентны.
- HTTP-ориентированные inbounds, такие как `XHTTP` и `WebSocket`, сейчас по умолчанию читают `X-Forwarded-For`. Если перед ними нет HTTP reverse proxy, которому вы доверяете, этот заголовок может быть подделан клиентом. Поэтому не используйте его напрямую для строгих решений безопасности, например для IP whitelist, blacklist или аудиторской атрибуции.
- Три HTTP-ориентированных inbound `XHTTP`, `WebSocket` и `HTTPUpgrade` по умолчанию доверяют `X-Forwarded-For`. Если перед ними нет доверенного HTTP reverse proxy, рекомендуется сочетать это с [`sockopt.trustedXForwardedFor`](../../config/transports/sockopt.md#trustedxforwardedfor), чтобы ограничить случаи доверия и не допустить подделки исходного IP клиентом.