- 让网站和 Reality 共用公网 443
- 把网站和 Xray 拆到本机后端端口
- 掌握 SNI 分流验证顺序
- 已有 Nginx HTTPS 网站
- Nginx 支持 stream_ssl_preread_module
- VPS IP 可以直连
来源与后续讨论
这里不是普通友情链接,而是读完文章后最应该跳转确认的地方:官网确认版本,GitHub 看源码和 Issue,第三方来源做交叉参考,X 帖子看后续补充和讨论。
VLESS + Reality + Nginx SNI 分流:网站和代理共用 443
这篇解决一个常见问题:服务器已经有 HTTPS 网站,443 被 Nginx 占用,但你仍然希望 Reality 使用 443 作为统一入口。
正确做法不是让 Xray 和 Nginx 抢同一个端口,而是让 Nginx 的 stream 模块在 TLS 解密前读取 SNI,并把不同请求转发到不同后端。
适合和不适合的场景
适合:
- VPS 上已经有 Nginx 网站。
- 网站必须继续使用 443。
- Reality 客户端仍希望连接 443。
- VPS IP 可以直连。
不适合:
- 你没有网站,443 端口空闲。这种情况直接看 Reality 基础版。
- 你需要隐藏源站 IP。这种情况还需要看 WS + Cloudflare 保底方案。
分流原理
外部请求 -> VPS:443 -> Nginx stream | |-- SNI=example.com -> Nginx HTTPS 网站:8080 |-- SNI=www.example.com -> Nginx HTTPS 网站:8080 |-- 其他 SNI -> Xray Reality:10443Reality 客户端通常使用伪装域名作为 SNI,例如 www.microsoft.com。Nginx stream 不解密 TLS,只读取 ClientHello 里的 SNI,然后把连接原样转发给对应后端。
前置检查
先确认 Nginx 是否带有 stream 和 ssl_preread 模块:
nginx -V 2>&1 | grep -E 'with-stream|with-stream_ssl_preread_module'如果没有输出,Debian/Ubuntu 可以尝试安装带 stream 模块的包:
apt updateapt install nginx-full -y再确认内部端口没有被占用:
ss -tulnp | grep -E ':8080|:10443'本文约定:
| 端口 | 用途 | 对外暴露 |
|---|---|---|
| 443 | Nginx stream 统一入口 | 是 |
| 8080 | 网站 HTTPS 后端 | 否,仅本机 |
| 10443 | Xray Reality 后端 | 否,仅本机 |
步骤一:安装 Xray 并生成参数
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install xray uuidxray x25519openssl rand -hex 8记录:
<UUID><PRIVATE_KEY><PUBLIC_KEY><SHORT_ID>
如果你已经从基础版迁移过来,可以复用原有参数。迁移时只需要把 Xray 从直接监听 443 改为监听本机 10443。
步骤二:配置 Xray 监听本机 10443
编辑:
vim /usr/local/etc/xray/config.json写入:
{ "log": { "loglevel": "warning" }, "inbounds": [ { "tag": "reality-in", "listen": "127.0.0.1", "port": 10443, "protocol": "vless", "settings": { "clients": [ { "id": "<UUID>", "flow": "xtls-rprx-vision" } ], "decryption": "none" }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "show": false, "dest": "www.microsoft.com:443", "serverNames": ["www.microsoft.com", "microsoft.com"], "privateKey": "<PRIVATE_KEY>", "shortIds": ["<SHORT_ID>"] } }, "sniffing": { "enabled": true, "destOverride": ["http", "tls", "quic"], "routeOnly": true } } ], "outbounds": [ { "protocol": "freedom", "tag": "direct" }, { "protocol": "blackhole", "tag": "block" } ], "routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "type": "field", "ip": ["geoip:private"], "outboundTag": "block" }, { "type": "field", "protocol": ["bittorrent"], "outboundTag": "block" } ] }}检查并启动:
xray -test -config /usr/local/etc/xray/config.jsonsystemctl daemon-reloadsystemctl enable --now xraysystemctl restart xrayss -tulnp | grep ':10443'步骤三:调整网站 HTTPS 监听端口
原来网站可能是:
server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;}现在要把它改成只监听本机 8080,其它不用动
server { listen 8080 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;}这样外部用户仍然访问 https://example.com,只是外层 443 由 stream 接住,再转发到本机 8080。
步骤四:加入 Nginx stream 分流
编辑:
vim /etc/nginx/nginx.conf在最外层加入 stream {},注意它必须和 http {} 平级,不要写进 http {} 里面。
stream { map $ssl_preread_server_name $backend { # 你原本的域名走 Nginx http 处理 example.com 127.0.0.1:8080; www.example.com 127.0.0.1:8080; # 其他 SNI(含 Reality 客户端)走 Xray default 127.0.0.1:10443; } server { listen 443; ssl_preread on; proxy_pass $backend; proxy_connect_timeout 10s; proxy_timeout 300s; }}检查并重载:
nginx -tsystemctl reload nginxss -tulnp | grep -E ':443|:8080|:10443'预期结果:
- Nginx 对外监听 443。
- Nginx 网站后端监听
127.0.0.1:8080。 - Xray Reality 监听
127.0.0.1:10443。
步骤五:配置防火墙
ufw allow 22/tcpufw allow 443/tcpufw deny 8080/tcpufw deny 10443/tcpufw enableufw status8080 和 10443 是本机后端端口,不应该对公网开放。云安全组也只需要放行 22 和 443,除非你有其他明确业务端口。
步骤六:验证网站链路
从服务器本机验证 8080 后端:
curl -kIv https://127.0.0.1:8080 \ -H 'Host: example.com' \ --resolve example.com:8080:127.0.0.1从外部验证 443 网站:
curl -Iv https://example.com如果网站证书、域名和页面都正常,说明网站分支没有被分流破坏。
步骤七:验证 Reality 分支
在服务器本机验证 Xray 后端端口存在:
ss -tlnp | grep ':10443'systemctl is-active xray再用客户端导入 Reality 节点。客户端参数仍然连接外部 443:
| 参数 | 值 |
|---|---|
| 地址 | <SERVER_IP> |
| 端口 | 443 |
| UUID | <UUID> |
| Flow | xtls-rprx-vision |
| 传输 | tcp |
| TLS | reality |
| SNI | www.microsoft.com |
| Fingerprint | chrome |
| PublicKey | <PUBLIC_KEY> |
| ShortId | <SHORT_ID> |
注意,客户端端口仍是 443,不是 10443。10443 只是服务器内部端口。
常见错误
stream 写进了 http 块
stream {} 必须和 http {} 同级。如果写进 http {},nginx -t 会报配置上下文错误。
网站后端仍然监听 443
如果网站配置仍然 listen 443 ssl;,Nginx stream 也要监听 443,端口会冲突。先把网站改到 127.0.0.1:8080 ssl。
把 10443 暴露到了公网
Reality 后端应该只监听 127.0.0.1:10443。如果写成 0.0.0.0:10443,相当于多暴露了一个入口,排错和安全面都会变大。
SNI 映射漏了主域名或 www
如果 example.com 映射了,但 www.example.com 没映射,访问 www 可能会被送进 Xray。把所有网站域名都加入 map。
小结
这一版的关键是“入口统一,后端隔离”:
- 外部只暴露 443。
- Nginx stream 按 SNI 决定流量去网站还是 Xray。
- 网站后端使用本机 8080。
- Reality 后端使用本机 10443。
- 客户端仍然连接服务器公网 IP 的 443。
如果你还需要源站隐藏或备用线路,下一篇继续看 VLESS + WebSocket + Cloudflare 保底方案。
按文章步骤复核自己的 VPS、域名、端口和客户端参数。
这篇已经可以直接看完,可以继续下一篇。
按顺序继续补齐上下文
同一 VLESS/Xray 自建代理系列的延伸阅读。
同一 VLESS/Xray 自建代理系列的延伸阅读。
同一 VLESS/Xray 自建代理系列的延伸阅读。
同一 VLESS/Xray 自建代理系列的延伸阅读。
同一 VLESS/Xray 自建代理系列的延伸阅读。
