mirror of
https://github.com/XTLS/Xray-docs-next.git
synced 2026-09-22 22:38:05 +03:00
Update VLESS Reverse Proxy
https://github.com/XTLS/Xray-core/pull/6110#issuecomment-4440102566 https://github.com/XTLS/Xray-core/pull/6110#issuecomment-4440168387
This commit is contained in:
@@ -20,6 +20,10 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
|
||||
{
|
||||
text: "Multiple Configurations",
|
||||
link: "/en/config/features/multiple.md"
|
||||
},
|
||||
{
|
||||
text: "Reverse Proxy / NAT Traversal",
|
||||
link: "/en/document/level-2/vless_reverse.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -14,7 +14,11 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
|
||||
link: "/config/features/browser_dialer.md"
|
||||
},
|
||||
{ text: "环境变量", link: "/config/features/env.md" },
|
||||
{ text: "多文件配置", link: "/config/features/multiple.md" }
|
||||
{ text: "多文件配置", link: "/config/features/multiple.md" },
|
||||
{
|
||||
text: "反向代理 / 内网穿透",
|
||||
link: "/document/level-2/vless_reverse.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -26,6 +26,10 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
|
||||
{
|
||||
text: "Конфигурация из нескольких файлов",
|
||||
link: "/ru/config/features/multiple.md"
|
||||
},
|
||||
{
|
||||
text: "Обратный прокси / NAT Traversal",
|
||||
link: "/ru/document/level-2/vless_reverse.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -7,3 +7,4 @@ Xray 具备以下特性:
|
||||
- [Browser Dialer](browser_dialer.md)
|
||||
- [环境变量](env.md)
|
||||
- [多文件配置](multiple.md)
|
||||
- [反向代理 / 内网穿透](/document/level-2/vless_reverse.md)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# 反向代理
|
||||
# 旧版反向代理
|
||||
|
||||
::: danger
|
||||
此功能已废弃,请使用 VLESS 反向代理
|
||||
旧版反向代理已废弃,请改用 [VLESS 反向代理](/document/level-2/vless_reverse.md)
|
||||
:::
|
||||
|
||||
:::: details 旧版反向代理文档(已废弃)
|
||||
反向代理可以把服务器端的流量向客户端转发,即逆向流量转发。
|
||||
|
||||
::: tip
|
||||
@@ -260,3 +261,5 @@ inbound:
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
@@ -433,3 +433,302 @@ VLESS 反向代理至少可以覆盖两类场景:
|
||||
- 让用户接入公网服务器后再通过反向通道漫游回家。
|
||||
|
||||
两者使用的是同一套反向连接机制,区别主要在公网侧如何路由流量,以及内网侧如何继续处理这些流量。理解这一点之后,就可以按自己的场景在“端口映射”和“远程漫游”之间自由扩展。
|
||||
|
||||
## 进阶技巧:高级负载均衡
|
||||
|
||||
如果公网端存在多个入站使用相同的 reverse tag,最终也只会对应产生一个出站;可以把它理解为多条线路同时挂在同一个可用池中,每次使用时随机选一路。
|
||||
|
||||
这种方式可以实现更灵活的多对多配置。假如某条线路暂时不可用,例如对应的内网端还没有连上来,那么它就不会进入当前可用池,后续流量会自动转发到其它仍然在线的线路上,无需手动切换。
|
||||
|
||||
不难看出,`reverse.tag` 在两侧都是“同 tag 合并为一个连接池”的语义:
|
||||
|
||||
- 公网侧多个 client 共用同一个 `reverse-out`,会收敛为同一个出站池;
|
||||
- 内网侧多个 VLESS 出站共用同一个 `reverse-in`,会收敛为同一个入口池。
|
||||
|
||||
所以它天然可以扩展成 N 对 N。更常见的实际部署是:对外只有一个业务域名,例如 `www.example.com`,再通过 GeoDNS 把访客就近分配到美西和东京两台公网服务器;而内网端则分别回连 `us-reverse.example.com` 和 `jp-reverse.example.com` 这两个公网节点。再部署两个内网端:家里和办公室。家里、办公室都分别连到美西和东京,于是每个公网端都会维护一个“家里 + 办公室”的可用池。实际转发时,会从当前已建立的连接里随机选一条可用线路;某一端离线后,它会自动从池里消失。
|
||||
|
||||
下面给一个极简片段,只保留 reverse 相关部分,继续沿用“公网入口端口映射到内网服务”的写法。
|
||||
|
||||
### 美西公网端
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 8443,
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "us-office-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"port": 443,
|
||||
"protocol": "tunnel",
|
||||
"tag": "portal"
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["portal"],
|
||||
"outboundTag": "reverse-out"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 东京公网端
|
||||
|
||||
完全同理,只是把 UUID 换成 `jp-home-uuid` 和 `jp-office-uuid`。
|
||||
|
||||
### 家里内网端
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-direct"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "us-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "jp-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "jp-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 办公室内网端
|
||||
|
||||
和家里内网端完全同理,只是把 UUID 换成 `us-office-uuid` 和 `jp-office-uuid`,并把 `redirect` 改成办公室要暴露的内网服务。
|
||||
|
||||
## 进阶技巧:透传真实访客 IP
|
||||
|
||||
如果你希望内网 Web 服务看到真实访客 IP,而不是把访问来源识别成内网侧 Xray 那台机器的 IP 地址,可以在内网侧的 `freedom` 出站里开启 `proxyProtocol`。不开启时,后端 WebServer 看到的源地址通常就是内网侧 Xray 的 IP;开启后,Xray 在把连接转发到 `redirect` 指定的后端时,会先发送一段 PROXY protocol 头,把真实源地址一并传给 WebServer。
|
||||
|
||||
例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
此时 `redirect` 指向的后端不能只是普通的 HTTP 监听,而必须显式开启 PROXY protocol。假设 WebServer 就是 `192.168.1.123`,而内网侧 Xray 的地址是 `192.168.1.10`,以 `nginx` 为例可以这样配置:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80 proxy_protocol;
|
||||
server_name _;
|
||||
|
||||
set_real_ip_from 192.168.1.10;
|
||||
real_ip_header proxy_protocol;
|
||||
|
||||
location / {
|
||||
root /srv/www/html;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上面的 `set_real_ip_from 192.168.1.10;` 表示只信任来自内网侧 Xray 的 PROXY protocol 头;这里的 `192.168.1.10` 只是示例,请改成你那台内网 Xray 的实际 IP。`proxyProtocol` 可选 `1` 或 `2`,只要后端支持,`nginx` 这一侧的写法保持不变。
|
||||
|
||||
## 进阶技巧:在内网侧按域名与访客 IP 精细分流
|
||||
|
||||
如果你希望外部能够访问到的内网站点不止一个,而且这些站点并不在同一台机器上,那么可以直接在反向代理入口上开启 `sniffing`,先从 HTTP Host 或 TLS SNI 中嗅探出域名,再按域名把流量送到不同的 `freedom` 出站。这样公网侧只需要保留一个入口,内网侧就能继续按站点拆分到不同主机。
|
||||
|
||||
同时,VLESS 反向代理会保留真实的访客源 IP,因此这些流量进入内网侧的路由系统后,还可以继续结合 `sourceIP` 做更细的控制,例如对某些来源直接 `blackhole`,或者把特定来源引导到另一组后端。下面给出一个组合示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"sourceIP": ["!geoip:cn"],
|
||||
"outboundTag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["full:admin.example.com"],
|
||||
"outboundTag": "reverse-admin"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["domain:blog.example.com"],
|
||||
"outboundTag": "reverse-blog"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
},
|
||||
{
|
||||
"protocol": "blackhole",
|
||||
"tag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-admin",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.10:8443",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.10",
|
||||
"port": "8443"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-blog",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.20:8080",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.20",
|
||||
"port": "8080"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-default",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.30:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.30",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "yourserver.com",
|
||||
"port": 8443,
|
||||
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
|
||||
"flow": "xtls-rprx-vision",
|
||||
"reverse": {
|
||||
"tag": "reverse-in",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
这个例子的要点是:
|
||||
|
||||
- `reverse.sniffing` 开在内网侧 VLESS 出站的 `reverse` 下,表示对从反向代理入口进来的连接执行嗅探;
|
||||
- 路由规则有先后顺序,所以像 `sourceIP -> blackhole` 这样的限制规则应当放在前面;
|
||||
- `proxyProtocol` 只负责把真实访客 IP 继续传给后端应用,如果你只想在 Xray 路由里按 `sourceIP` 分流,也可以不启用它。
|
||||
|
||||
这样配置后,一个公网入口就可以同时承接多个内网站点,并且还能在内网侧根据访客来源地址继续做拒绝、分流、审计等更灵活的处理。
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
下面这些点更偏部署安全与边界控制,建议在正式使用前通读一遍:
|
||||
|
||||
- 用于反向代理的 UUID 无法与正向代理(普通客户端)共用,只能单独新建。此外反向代理 UUID 要妥善保管,否则一旦客户端配置泄露,攻击者就可能尝试劫持你的反向代理通道。
|
||||
- 用于内网穿透的那条连接,即使开启了 `XTLS Vision`,当前主要获得的也是 `padding` 等收益,并不等同于常说的“裸奔”效果。至于面向最终用户的那条连接是否也要开启 XTLS,需要结合你的链路形态和威胁模型自行评估。
|
||||
- 承接反向代理流量的内网 `freedom`(也就是常说的 `direct`)出站,建议按最小权限原则配置。把默认出站设为 `blackhole`,只把允许访问的目标显式路由到专用 `freedom`。再通过 `finalRules` 只放行必要的地址和端口。
|
||||
- 如果你使用的是别人提供的穿透服务用于远程回家,或者你并不完全信任公网 VPS,建议不要让反向代理流量直接落到真实内网业务。可以在内网再部署一个带 `VLESS Encryption` 的服务端专门承接这部分流量,再由它转发给实际业务,以补上身份认证和数据保护,否则有权限接触到公网服务器的人可以漫游你的内网。
|
||||
- 通过 `VLESS` 等入站协议把流量送到内网端时,路由系统里看到的 `Source` / `Local` 所属协议,不一定与最终 `Target` 一致。涉及 `source`、`local`、`network` 等条件时,应以实际流量形态为准,不要想当然地把它们等同起来。
|
||||
- `XHTTP`、`WebSocket` 等基于 HTTP 的入站当前会默认读取 `X-Forwarded-For`。如果前面没有你自己信任的 HTTP 反向代理,这个头可以被客户端伪造,因此不要直接拿它做严格的安全判断,例如 IP 白名单、黑名单或审计归因。
|
||||
|
||||
@@ -7,3 +7,4 @@ Xray has the following features:
|
||||
- [Browser Dialer](browser_dialer.md)
|
||||
- [Environment Variables](env.md)
|
||||
- [Multiple File Configuration](multiple.md)
|
||||
- [Reverse Proxy / NAT Traversal](/en/document/level-2/vless_reverse.md)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Reverse Proxy
|
||||
# Legacy Reverse Proxy
|
||||
|
||||
::: danger
|
||||
This feature has been deprecated. Please use the VLESS reverse proxy.
|
||||
The legacy reverse proxy has been deprecated. Please use the [VLESS reverse proxy](/en/document/level-2/vless_reverse.md).
|
||||
:::
|
||||
|
||||
:::: details Legacy reverse proxy documentation (deprecated)
|
||||
A reverse proxy can forward traffic from the server side to the client side, effectively performing reverse traffic forwarding.
|
||||
|
||||
::: tip
|
||||
@@ -262,3 +263,5 @@ Routing Configuration:
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
@@ -433,3 +433,302 @@ VLESS reverse proxy can cover at least two types of scenarios:
|
||||
- Let users connect to a public server and then roam back home through the reverse tunnel.
|
||||
|
||||
Both use the same reverse connection mechanism. The main difference lies in how the public side routes the traffic and how the private side continues processing it. Once you understand that, you can freely extend the model between "port mapping" and "remote roaming" according to your own needs.
|
||||
|
||||
## Advanced Technique: Advanced Load Balancing
|
||||
|
||||
If multiple inbounds on the public side use the same reverse tag, they still end up producing only one outbound. You can think of this as multiple lines hanging off the same availability pool, with one live line chosen at random each time it is used.
|
||||
|
||||
This makes more flexible many-to-many setups possible. If one line is temporarily unavailable, for example because the corresponding internal device has not connected yet, it simply does not enter the current availability pool. Subsequent traffic is then forwarded automatically to other lines that are still online, with no manual switching required.
|
||||
|
||||
In other words, `reverse.tag` has the same "same tag means merge into one connection pool" semantics on both sides:
|
||||
|
||||
- Multiple clients on the public side that share the same `reverse-out` converge into one outbound pool;
|
||||
- Multiple VLESS outbounds on the internal side that share the same `reverse-in` converge into one inbound pool.
|
||||
|
||||
So it naturally scales to N-to-N. A more common real deployment looks like this: externally there is only one service domain, for example `www.example.com`, and GeoDNS sends visitors to the nearest public server in Los Angeles or Tokyo. On the internal side, connections are established back to `us-reverse.example.com` and `jp-reverse.example.com`. Then deploy two internal devices, one at home and one in the office. Both home and office connect to both Los Angeles and Tokyo, so each public node maintains an availability pool of "home + office". During actual forwarding, one available line is selected at random from the currently established connections. If one endpoint goes offline, it disappears from the pool automatically.
|
||||
|
||||
Below is a minimal snippet that keeps only the reverse-related parts and continues using the "public entry port mapped to an internal service" style.
|
||||
|
||||
### Los Angeles Public Server
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 8443,
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "us-office-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"port": 443,
|
||||
"protocol": "tunnel",
|
||||
"tag": "portal"
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["portal"],
|
||||
"outboundTag": "reverse-out"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Tokyo Public Server
|
||||
|
||||
Exactly the same idea, except that the UUIDs are changed to `jp-home-uuid` and `jp-office-uuid`.
|
||||
|
||||
### Home Internal Device
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-direct"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "us-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "jp-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "jp-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Office Internal Device
|
||||
|
||||
Exactly the same as the home internal device, except that the UUIDs are changed to `us-office-uuid` and `jp-office-uuid`, and `redirect` is changed to the internal service that the office side should expose.
|
||||
|
||||
## Advanced Technique: Preserve the Real Visitor IP
|
||||
|
||||
If you want the internal Web service to see the real visitor IP instead of identifying the source as the internal-side Xray machine, you can enable `proxyProtocol` on the internal-side `freedom` outbound. If it is not enabled, the backend Web server usually sees the source address of the internal-side Xray machine. If it is enabled, Xray sends a PROXY protocol header first when forwarding the connection to the backend specified by `redirect`, so that the real source address is passed along to the Web server.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In that case, the backend pointed to by `redirect` cannot just be an ordinary HTTP listener. It must explicitly enable PROXY protocol as well. Suppose the Web server is `192.168.1.123` and the internal-side Xray address is `192.168.1.10`. With `nginx`, for example, it can be configured like this:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80 proxy_protocol;
|
||||
server_name _;
|
||||
|
||||
set_real_ip_from 192.168.1.10;
|
||||
real_ip_header proxy_protocol;
|
||||
|
||||
location / {
|
||||
root /srv/www/html;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `set_real_ip_from 192.168.1.10;` line above means that only the PROXY protocol header sent by the internal-side Xray is trusted. `192.168.1.10` here is only an example; replace it with the actual IP of your internal Xray machine. `proxyProtocol` can be either `1` or `2`. As long as the backend supports it, the `nginx` side configuration remains the same.
|
||||
|
||||
## Advanced Technique: Fine-Grained Routing by Domain and Visitor IP on the Internal Side
|
||||
|
||||
If you want external users to reach more than one internal site and those sites are not all on the same machine, you can enable `sniffing` directly on the reverse proxy entry, extract the domain name from the HTTP Host or TLS SNI, and then route traffic by domain to different `freedom` outbounds. This way the public side keeps only one entry, while the internal side can still fan traffic out to different hosts by site.
|
||||
|
||||
At the same time, the VLESS reverse proxy preserves the real visitor source IP. Once the traffic enters the internal-side routing system, you can continue using `sourceIP` for finer control, for example sending some sources directly to `blackhole`, or steering specific sources to another backend group. Here is a combined example:
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"sourceIP": ["!geoip:cn"],
|
||||
"outboundTag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["full:admin.example.com"],
|
||||
"outboundTag": "reverse-admin"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["domain:blog.example.com"],
|
||||
"outboundTag": "reverse-blog"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
},
|
||||
{
|
||||
"protocol": "blackhole",
|
||||
"tag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-admin",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.10:8443",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.10",
|
||||
"port": "8443"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-blog",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.20:8080",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.20",
|
||||
"port": "8080"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-default",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.30:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.30",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "yourserver.com",
|
||||
"port": 8443,
|
||||
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
|
||||
"flow": "xtls-rprx-vision",
|
||||
"reverse": {
|
||||
"tag": "reverse-in",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The key points of this example are:
|
||||
|
||||
- `reverse.sniffing` is enabled under `reverse` on the internal-side VLESS outbound, which means sniffing is performed on connections entering from the reverse proxy entry;
|
||||
- Routing rules are evaluated in order, so restrictive rules like `sourceIP -> blackhole` should be placed first;
|
||||
- `proxyProtocol` is only used to pass the real visitor IP further to the backend application. If you only want to route inside Xray by `sourceIP`, you can leave it disabled.
|
||||
|
||||
With this setup, one public entry can serve multiple internal sites, and the internal side can still perform more flexible rejection, steering, and auditing based on the visitor source address.
|
||||
|
||||
## Security Notes
|
||||
|
||||
The following points are more about deployment safety and boundary control. It is recommended to read through them before using this in production:
|
||||
|
||||
- A UUID used for reverse proxying cannot be shared with normal forward proxy clients. It must be created separately. Also, reverse proxy UUIDs should be protected carefully. Once a client configuration leaks, an attacker may try to hijack your reverse proxy tunnel.
|
||||
- For the connection used in private network penetration, even if `XTLS Vision` is enabled, the current practical benefits are still mainly things like `padding`. It is not the same as the commonly discussed "direct exposure" effect. Whether the connection facing end users should also enable XTLS depends on your actual link structure and threat model.
|
||||
- The internal `freedom` outbound that receives reverse proxy traffic, often called the `direct` outbound, should be configured according to the principle of least privilege. Set the default outbound to `blackhole`, only route explicitly allowed targets to a dedicated `freedom`, and then use `finalRules` to allow only the necessary addresses and ports.
|
||||
- If you are using a penetration service provided by someone else for remote access home, or if you do not fully trust the public VPS, it is recommended not to let reverse proxy traffic land directly on your real internal services. Instead, deploy another server on the internal side with `VLESS Encryption` enabled specifically to receive that traffic, and let it forward traffic to the actual service. This adds authentication and data protection; otherwise anyone with sufficient access to the public server may be able to roam through your internal network.
|
||||
- When traffic is delivered to the internal side through inbound protocols such as `VLESS`, the protocol shown by `Source` or `Local` in the routing system is not necessarily the same as the final `Target`. When using conditions such as `source`, `local`, or `network`, rely on the actual traffic shape instead of assuming they are all equivalent.
|
||||
- HTTP-based inbounds such as `XHTTP` and `WebSocket` currently read `X-Forwarded-For` by default. If there is no HTTP reverse proxy in front that you trust, the header can be forged by the client. Therefore, do not use it directly for strict security decisions such as IP whitelists, blacklists, or audit attribution.
|
||||
|
||||
@@ -7,3 +7,4 @@ Xray предлагает следующие функции:
|
||||
- [Browser Dialer](browser_dialer.md)
|
||||
- [Переменные окружения](env.md)
|
||||
- [Конфигурация из нескольких файлов](multiple.md)
|
||||
- [Обратный прокси / NAT Traversal](/ru/document/level-2/vless_reverse.md)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Обратный прокси
|
||||
# Устаревший обратный прокси
|
||||
|
||||
::: danger
|
||||
Эта функция устарела. Пожалуйста, используйте обратный прокси-сервер VLESS.
|
||||
Устаревший обратный прокси снят с поддержки. Пожалуйста, используйте [обратный прокси VLESS](/ru/document/level-2/vless_reverse.md).
|
||||
:::
|
||||
|
||||
:::: details Документация по устаревшему обратному прокси (снято с поддержки)
|
||||
Обратный прокси может перенаправлять трафик с сервера на клиент, то есть выполнять обратную переадресацию трафика.
|
||||
|
||||
::: tip
|
||||
@@ -262,3 +263,5 @@ inbound:
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
@@ -433,3 +433,302 @@ sequenceDiagram
|
||||
- Подключение пользователя к публичному серверу с последующим возвратом домой через обратный туннель.
|
||||
|
||||
Оба сценария используют один и тот же механизм обратного соединения. Основное различие состоит в том, как публичная сторона маршрутизирует трафик и как внутренняя сторона продолжает его обрабатывать. Поняв это, можно свободно расширять схему между "пробросом порта" и "удаленным возвращением домой" под свои задачи.
|
||||
|
||||
## Продвинутые Приемы: Расширенная Балансировка Нагрузки
|
||||
|
||||
Если на публичной стороне несколько входящих подключений используют один и тот же reverse tag, в итоге все равно будет создан только один outbound. Это можно понимать как несколько линий, подвешенных к одному общему пулу доступности, где при каждом использовании случайно выбирается одна из живых линий.
|
||||
|
||||
Такой подход позволяет строить более гибкие конфигурации many-to-many. Если какая-то линия временно недоступна, например потому что соответствующее внутреннее устройство еще не подключилось, она просто не попадет в текущий пул доступности. Последующий трафик будет автоматически перенаправляться на другие линии, которые все еще в сети, без ручного переключения.
|
||||
|
||||
Иначе говоря, у `reverse.tag` с обеих сторон одна и та же семантика: "одинаковый tag объединяется в один пул соединений":
|
||||
|
||||
- Несколько клиентов на публичной стороне, использующих один и тот же `reverse-out`, сходятся в один пул outbound;
|
||||
- Несколько VLESS outbound на внутренней стороне, использующих один и тот же `reverse-in`, сходятся в один пул inbound.
|
||||
|
||||
Поэтому схема естественно масштабируется до N-к-N. Более типичный реальный сценарий выглядит так: снаружи есть только один сервисный домен, например `www.example.com`, а GeoDNS отправляет посетителей на ближайший публичный сервер в Лос-Анджелесе или Токио. На внутренней стороне при этом устанавливаются соединения назад к `us-reverse.example.com` и `jp-reverse.example.com`. Затем разворачиваются два внутренних устройства: дома и в офисе. И дом, и офис подключаются и к Лос-Анджелесу, и к Токио, поэтому каждый публичный узел поддерживает пул доступности вида "дом + офис". При реальной переадресации случайно выбирается одна доступная линия из уже установленных соединений. Если одна из точек уходит офлайн, она автоматически исчезает из пула.
|
||||
|
||||
Ниже приведен минимальный фрагмент, в котором оставлены только части, связанные с reverse, и по-прежнему используется модель "публичный входной порт отображается на внутренний сервис".
|
||||
|
||||
### Публичный Сервер В Лос-Анджелесе
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 8443,
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "us-office-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-out"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"port": 443,
|
||||
"protocol": "tunnel",
|
||||
"tag": "portal"
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["portal"],
|
||||
"outboundTag": "reverse-out"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Публичный Сервер В Токио
|
||||
|
||||
Полностью та же идея, только UUID меняются на `jp-home-uuid` и `jp-office-uuid`.
|
||||
|
||||
### Домашнее Внутреннее Устройство
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-direct"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "us-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "us-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "jp-reverse.example.com",
|
||||
"port": 8443,
|
||||
"id": "jp-home-uuid",
|
||||
"reverse": {
|
||||
"tag": "reverse-in"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Офисное Внутреннее Устройство
|
||||
|
||||
Полностью аналогично домашнему внутреннему устройству, только UUID меняются на `us-office-uuid` и `jp-office-uuid`, а `redirect` нужно заменить на тот внутренний сервис, который должен публиковаться из офиса.
|
||||
|
||||
## Продвинутые Приемы: Передача Реального IP Посетителя
|
||||
|
||||
Если вы хотите, чтобы внутренний Web-сервис видел реальный IP посетителя, а не определял источник как IP машины с Xray на внутренней стороне, можно включить `proxyProtocol` у outbound `freedom` на внутренней стороне. Если он выключен, backend Web-сервер обычно видит адрес самой внутренней машины с Xray. Если он включен, Xray перед пересылкой соединения на backend, указанный в `redirect`, сначала отправляет заголовок PROXY protocol, чтобы вместе с ним передать Web-серверу и реальный исходный адрес.
|
||||
|
||||
Например:
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-direct",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.123:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.123",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
В этом случае backend, на который указывает `redirect`, не может быть просто обычным HTTP listener. На нем также нужно явно включить поддержку PROXY protocol. Предположим, что Web-сервер расположен по адресу `192.168.1.123`, а адрес внутреннего Xray — `192.168.1.10`. Для `nginx`, например, конфигурация может выглядеть так:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80 proxy_protocol;
|
||||
server_name _;
|
||||
|
||||
set_real_ip_from 192.168.1.10;
|
||||
real_ip_header proxy_protocol;
|
||||
|
||||
location / {
|
||||
root /srv/www/html;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Строка `set_real_ip_from 192.168.1.10;` выше означает, что доверять нужно только PROXY protocol header, пришедшему от внутреннего Xray. `192.168.1.10` здесь приведен лишь как пример; замените его на реальный IP вашей внутренней машины с Xray. `proxyProtocol` может быть равен `1` или `2`. Если backend это поддерживает, конфигурация на стороне `nginx` остается той же.
|
||||
|
||||
## Продвинутые Приемы: Точная Маршрутизация По Домену И IP Посетителя На Внутренней Стороне
|
||||
|
||||
Если вы хотите, чтобы извне были доступны сразу несколько внутренних сайтов, и эти сайты находятся не на одной машине, можно включить `sniffing` прямо на входе обратного прокси, извлечь доменное имя из HTTP Host или TLS SNI, а затем по домену отправлять трафик в разные outbound `freedom`. Так публичная сторона сохранит только одну точку входа, а внутренняя сторона все равно сможет разводить трафик по разным хостам в зависимости от сайта.
|
||||
|
||||
При этом обратный прокси VLESS сохраняет реальный source IP посетителя. Когда трафик попадает во внутреннюю систему маршрутизации, можно продолжить использовать `sourceIP` для более точного контроля, например отправлять некоторые источники сразу в `blackhole` или направлять определенные источники в другую группу backend-серверов. Ниже приведен комбинированный пример:
|
||||
|
||||
```json
|
||||
{
|
||||
"routing": {
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"sourceIP": ["!geoip:cn"],
|
||||
"outboundTag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["full:admin.example.com"],
|
||||
"outboundTag": "reverse-admin"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"domain": ["domain:blog.example.com"],
|
||||
"outboundTag": "reverse-blog"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["reverse-in"],
|
||||
"outboundTag": "reverse-default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
},
|
||||
{
|
||||
"protocol": "blackhole",
|
||||
"tag": "reverse-block"
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-admin",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.10:8443",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.10",
|
||||
"port": "8443"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-blog",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.20:8080",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.20",
|
||||
"port": "8080"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"tag": "reverse-default",
|
||||
"settings": {
|
||||
"redirect": "192.168.1.30:80",
|
||||
"proxyProtocol": 1,
|
||||
"finalRules": [
|
||||
{
|
||||
"action": "allow",
|
||||
"network": "tcp",
|
||||
"ip": "192.168.1.30",
|
||||
"port": "80"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"address": "yourserver.com",
|
||||
"port": 8443,
|
||||
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
|
||||
"flow": "xtls-rprx-vision",
|
||||
"reverse": {
|
||||
"tag": "reverse-in",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Ключевые моменты этого примера:
|
||||
|
||||
- `reverse.sniffing` включается внутри `reverse` у внутреннего VLESS outbound, то есть sniffing выполняется для соединений, пришедших через вход обратного прокси;
|
||||
- Правила маршрутизации проверяются по порядку, поэтому ограничительные правила вроде `sourceIP -> blackhole` нужно ставить раньше;
|
||||
- `proxyProtocol` нужен только для того, чтобы передавать реальный IP посетителя дальше в backend-приложение. Если вам нужна только маршрутизация внутри Xray по `sourceIP`, его можно не включать.
|
||||
|
||||
С такой конфигурацией одна публичная точка входа может обслуживать сразу несколько внутренних сайтов, а внутренняя сторона при этом сохраняет возможность более гибко отбрасывать, маршрутизировать и аудировать трафик по адресу источника посетителя.
|
||||
|
||||
## Замечания По Безопасности
|
||||
|
||||
Следующие пункты больше относятся к безопасному развертыванию и контролю границ. Рекомендуется внимательно прочитать их перед использованием этой схемы в продакшене:
|
||||
|
||||
- UUID, используемый для обратного проксирования, нельзя разделять с обычными клиентами прямого прокси. Его нужно создавать отдельно. Кроме того, UUID для обратного прокси нужно бережно хранить: если конфигурация клиента утечет, злоумышленник может попытаться перехватить ваш reverse tunnel.
|
||||
- Для соединения, используемого в сценарии внутреннего проникновения, даже при включенном `XTLS Vision` практический выигрыш сейчас в основном ограничивается такими вещами, как `padding`. Это не то же самое, что часто обсуждаемый эффект "прямого оголенного канала". Нужно ли также включать XTLS на соединении, обращенном к конечным пользователям, зависит от вашей реальной топологии и модели угроз.
|
||||
- Внутренний 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 или аудиторской атрибуции.
|
||||
|
||||
Reference in New Issue
Block a user