站点与 Xray 共用 443 反向代理 —— Nginx Stream
网站域名访问与 3x-ui 中的 Xray 节点都需要使用 443 端口时,如果 Nginx 和 Xray 同时监听同一个公网 IP 的 443 端口,会发生端口冲突,导致网站无法访问或者 VLESS TLS / Reality 节点无法正常连接。
本教程使用 Nginx stream + ssl_preread 作为公网 443 的统一入口,由 Nginx 在四层读取 TLS ClientHello 中的 SNI,但不解密代理节点流量,然后将不同 SNI 的连接转发到不同的本地服务,实现网站与 3x-ui/Xray 共用公网 443 端口。
与 v2ray-agent 的 Xray fallback 方案不同,本教程中 公网 443 由 Nginx stream 监听,3x-ui 中使用 443 的 Xray 入站改为仅监听 127.0.0.1:443。客户端仍然连接服务器公网 IP 的 443 端口,127.0.0.1:443 只是服务器内部转发端口。
教程示例环境:
3x-ui / Xray → 公网 443 → 内部 127.0.0.1:443
VLESS Reality Vision → 443
VLESS TCP TCP/TLS Vision → 443 或其他独立端口
Komari 面板 → https://komari.10181128.xyz → 127.0.0.1:8083
OpenList 网盘 → https://alist.10181128.xyz → 127.0.0.1:5244
PanSou 盘搜 → https://pansou.10181128.xyz → 127.0.0.1:8107
服务器公网 IP → 69.63.216.218
Reality 的 SNI 可以使用 www.amd.com、Amazon、Cloudflare 等不同目标域名,只要不与实际网站域名冲突,就会自动进入 default → Xray,无需每次修改 Nginx 配置。
准备工作:
- 一台 Debian / Ubuntu 服务器,并获取服务器公网 IP。
- 公网 IP 已直接绑定到服务器网卡。
- 域名已解析到当前服务器。
- 3x-ui 已安装,并已创建 VLESS TLS / Reality 入站。
- Komari、OpenList、PanSou 等网站服务已安装并监听自己的内部端口。
- 系统 Nginx 已安装。
- 本教程示例中的公网 IP、域名和端口需要替换成自己的实际配置。
最终可以实现:
1 | 浏览器 / 代理客户端 |
一、部署 3x-ui 与 Komari、OpenList、PanSou
3x-ui 正常安装并创建 Xray 入站。
例如:
1 | Reality: |
Komari、OpenList、PanSou 使用 Docker 或系统服务运行,只监听各自的业务端口。例如:
1 | Komari -> 0.0.0.0:8083 |
如果 Docker 实际显示为容器内部端口映射,例如:
1 | 0.0.0.0:8083->25774/tcp |
也没有问题,后续 Nginx 只需要反代宿主机实际暴露的 8083 / 5244 / 8107。
不要让 Docker 中的 Nginx、Caddy、Traefik 等容器再占用宿主机 80/443。
查看容器:
1 | docker ps -a |
查看端口:
1 | ss -lntp | grep -E ':(80|443|8083|5244|8107|58587)\b' |
在配置 443 共用之前,可能看到:
1 | *:443 -> xray reality |
其中当前直接占用公网 443 的是 Xray。
二、确认公网 IP 是否直接绑定到服务器
本教程为了让:
1 | 69.63.216.218:443 -> Nginx |
同时存在,需要公网 IP 确实是服务器本机地址。
执行:
1 | ip -4 addr show | grep -F '69.63.216.218' |
正常示例:
1 | inet 69.63.216.218/32 brd 69.63.216.218 scope global eth0 |
说明公网 IP 已直接绑定到网卡,可以继续使用本教程的方案。
如果没有任何输出,说明服务器可能位于上游 NAT 后面。此时不要让 Nginx
listen 公网IP:443,应改用:
1
2 Nginx -> 0.0.0.0:443
Xray -> 127.0.0.1:32443并将 stream 中的
default改为127.0.0.1:32443。
三、检查 Nginx stream 与 ssl_preread
执行:
1 | nginx -V 2>&1 | tr ' ' '\n' | grep stream |
理想状态:
1 | --with-stream |
其中最关键的是:
1 | --with-stream |
ssl_preread 可以在不终止 TLS 的情况下读取 ClientHello 中的 SNI,然后按域名进行四层 TCP 分流。
如果:
1 | ls -l /usr/lib/nginx/modules/ngx_stream_module.so |
没有文件,但 nginx -V 已经显示 --with-stream,说明 stream 已静态编译进 Nginx,属于正常情况,不需要再安装动态模块。
四、准备 Komari / OpenList / PanSou HTTPS 证书
假设三个网站域名分别为:
1 | Komari -> komari.10181128.xyz |
先确认域名已经解析到当前服务器公网 IP:
1 | dig +short komari.10181128.xyz |
1. 如果 acme.sh 已经存在证书
分别检查:
1 | openssl x509 \ |
1 | openssl x509 \ |
1 | openssl x509 \ |
2. 如果还没有证书
使用 standalone 方式申请时需要保证 80 端口暂时空闲。若 Nginx 已经启动,可临时停止:
1 | systemctl stop nginx |
设置默认 CA:
1 | /root/.acme.sh/acme.sh --set-default-ca --server letsencrypt |
申请 Komari:
1 | /root/.acme.sh/acme.sh --issue \ |
申请 OpenList:
1 | /root/.acme.sh/acme.sh --issue \ |
申请 PanSou:
1 | /root/.acme.sh/acme.sh --issue \ |
3. 安装到 Nginx 独立证书目录
创建目录:
1 | mkdir -p /etc/nginx/ssl |
安装 Komari:
1 | install -m 644 \ |
安装 OpenList:
1 | install -m 644 \ |
安装 PanSou:
1 | install -m 644 \ |
检查:
1 | ls -l /etc/nginx/ssl/ |
应该至少存在:
1 | komari.10181128.xyz.crt |
网站 HTTPS 证书由内部 Nginx 使用。
如果 3x-ui 的 443 入站是 VLESS TLS,则 Xray TLS 节点自己的证书仍然在 3x-ui/Xray 中单独配置;Nginx stream 不会替 Xray 终止 TLS。
Reality 本身不需要普通网站 TLS 证书。
五、配置 Komari / OpenList / PanSou 内部 HTTPS
为了便于管理,三个网站统一写在:
1 | nano /etc/nginx/conf.d/services.conf |
如果之前已经单独创建了 /etc/nginx/conf.d/komari.conf,可以删除其中重复的 Komari server 块后,统一改用下面这个 services.conf;不要让两个配置文件同时存在相同的 server_name + listen 配置。
写入:
1 | map $http_upgrade $connection_upgrade { |
测试:
1 | nginx -t |
启动并设置开机自启:
1 | systemctl enable --now nginx |
此时 Nginx 只监听:
1 | 0.0.0.0:80 |
还没有接管公网 443,所以不会影响当前正在工作的 Xray 443。
1. 测试内部 Komari
1 | curl -sk \ |
2. 测试内部 OpenList
1 | curl -sk \ |
3. 测试内部 PanSou
1 | curl -sk \ |
正常一般会返回:
1 | HTTP 200 |
部分应用如果自身有跳转,也可能返回 301 / 302。
六、配置 Nginx stream 公网 443 分流
先备份 Nginx 主配置:
1 | cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak-20260827 |
创建 stream 配置目录:
1 | mkdir -p /etc/nginx/stream.d |
创建:
1 | nano /etc/nginx/stream.d/443.conf |
写入:
1 | map $ssl_preread_server_name $backend_443 { |
其中:
1 | komari.10181128.xyz 127.0.0.1:31302; |
表示网站流量进入 Komari 内部 HTTPS。
而:
1 | default 127.0.0.1:443; |
表示其他所有流量全部进入 Xray。
因此 Reality 的 SNI 无论是:
1 | www.amd.com |
都不需要额外写进 Nginx,自动走:
1 | default → 127.0.0.1:443 → Xray |
不要把 Reality 或 VLESS TLS 节点的 SNI 设置成
komari.10181128.xyz、alist.10181128.xyz、pansou.10181128.xyz,否则会被 Nginx 分流到对应的网站服务。
七、在 nginx.conf 中加载 stream 配置
查看:
1 | cat /etc/nginx/nginx.conf |
在整个 http {} 块结束后增加:
1 | stream { |
结构应为:
1 | events { |
注意:
stream {}必须与http {}同级,不能写进http {}内部。
检查:
1 | nginx -t |
如果成功,此时 先不要 reload Nginx。
因为 Xray 仍可能监听:
1 | *:443 |
如果现在让 Nginx 加载:
1 | 69.63.216.218:443 |
会与 Xray 当前的 0.0.0.0:443 冲突。
八、修改 3x-ui 的 443 入站监听地址
进入:
1 | 3x-ui |
如果当前是:
1 | 监听 IP:留空 |
留空通常代表:
1 | 0.0.0.0:443 |
修改为:
1 | 监听 IP:127.0.0.1 |
只修改监听 IP,不修改端口。
如果当前为 Reality:
1 | 安全:Reality |
这些全部保持不变。
UUID、Flow、Private Key、Public Key、Short ID 也全部保持不变。
保存后检查:
1 | ss -lntp | grep ':443' |
应该看到:
1 | 127.0.0.1:443 -> xray |
而不应再看到:
1 | *:443 -> xray |
只有使用 443 的 Xray 入站需要改成
127.0.0.1。例如另一个 TLS 入站为 58587,如果仍需要公网直接访问 58587,监听 IP 可以继续留空,无需修改。
核心规则:
1
2
3
4
5 Xray 入站端口 = 443
→ Listen IP = 127.0.0.1
Xray 入站端口 ≠ 443,且需要公网直连
→ Listen IP 可以留空
九、让 Nginx 接管公网 443 并测试
确认 Xray 已变为:
1 | 127.0.0.1:443 |
后执行:
1 | nginx -t && systemctl reload nginx |
然后:
1 | ss -lntp | grep ':443' |
最终理想状态:
1 | 69.63.216.218:443 -> nginx |
这就是本方案最关键的最终状态。
1. 测试 Komari
浏览器打开:
1 | https://komari.10181128.xyz |
或者:
1 | curl -sk \ |
正常应返回:
1 | HTTP 200 |
2. 测试 Reality / TLS
Clash Verge Rev 等客户端仍然连接:
1 | 服务器:69.63.216.218 |
客户端无需改成内部端口。
如果 Komari、OpenList、PanSou、Reality、TLS 均正常,则说明 443 共用成功。
十、共用 443 成功后的端口状态
执行:
1 | docker ps -a |
理想状态:
1 | 69.63.216.218:443 -> nginx |
最终架构:
1 | 公网 443 |
十一、配置证书自动续期与 Nginx 开机自启
acme.sh 不应该只更新 /root/.acme.sh/ 中的原始证书,还需要在续期成功后自动部署到 /etc/nginx/ssl/。
1. Komari
1 | /root/.acme.sh/acme.sh --install-cert \ |
2. OpenList
1 | /root/.acme.sh/acme.sh --install-cert \ |
3. PanSou
1 | /root/.acme.sh/acme.sh --install-cert \ |
检查三个证书的部署路径:
1 | grep -E "Le_RealKeyPath|Le_RealFullChainPath|Le_ReloadCmd" \ |
1 | grep -E "Le_RealKeyPath|Le_RealFullChainPath|Le_ReloadCmd" \ |
1 | grep -E "Le_RealKeyPath|Le_RealFullChainPath|Le_ReloadCmd" \ |
Le_ReloadCmd 可能以 Base64 编码形式保存,这是正常现象。
检查 acme.sh cron:
1 | crontab -l | grep acme.sh |
确保 Nginx 开机启动:
1 | systemctl enable nginx |
正常:
1 | enabled |
十二、备份当前可用配置
成功后建议立即备份。
1 | mkdir -p /root/3xui-443-backup |
3x-ui 本身建议同时使用面板自带的 备份 / 导出数据库 功能备份入站、用户、订阅和面板设置。
十三、常见问题
1. Nginx reload 后提示 443 地址已被占用
检查:
1 | ss -lntp | grep ':443' |
如果仍然看到:
1 | *:443 -> xray |
说明 3x-ui 的 443 入站监听 IP 仍然留空或为 0.0.0.0,需要改成:
1 | 127.0.0.1 |
保存后再执行:
1 | nginx -t && systemctl reload nginx |
2. 为什么 Nginx 不能写 listen 0.0.0.0:443
因为本方案中 Xray 使用:
1 | 127.0.0.1:443 |
而 0.0.0.0:443 代表监听所有本地 IPv4 地址,其中也包括 127.0.0.1,会与 Xray 冲突。
因此公网 IP 直接绑定服务器时,应明确写:
1 | listen 69.63.216.218:443; |
这样可以同时存在:
1 | 69.63.216.218:443 -> nginx |
3. Reality 更换 AMD / Amazon / Cloudflare SNI 后是否要改 Nginx
不需要。
因为:
1 | default 127.0.0.1:443; |
会把除实际网站域名之外的其他 SNI 全部送给 Xray。
只有当 Reality SNI 与网站域名完全相同时才会冲突,例如不要设置:
1 | Reality SNI = komari.10181128.xyz |
4. VLESS TLS 和 Reality 都能用 443 吗
可以。
如果只是有时 TLS 用 443、有时 Reality 用 443,则当前使用 443 的入站统一设置:
1 | Listen IP = 127.0.0.1 |
Nginx 不关心内部是 TLS 还是 Reality。
如果 TLS 和 Reality 需要同时使用公网 443,则给它们分配不同内部端口,再按 SNI 分流,例如:
1 | TLS -> 127.0.0.1:31443 |
5. Komari / OpenList / PanSou 内部测试正常,公网域名打不开
检查:
1 | nginx -t |
必须确认 DNS 指向当前公网 IP,并且 443 状态为:
1 | 公网IP:443 -> nginx |
6. Komari / OpenList / PanSou 证书文件不存在
例如:
1 | cannot load certificate key "/etc/nginx/ssl/komari.10181128.xyz.key" |
检查:
1 | ls -l /etc/nginx/ssl/ |
三个域名都必须同时存在 .crt 和 .key:
1 | komari.10181128.xyz.crt |
7. 证书续期后 Nginx 仍然使用旧证书
检查 acme.sh 是否已经把三个域名的安装路径分别指向:
1 | /etc/nginx/ssl/komari.10181128.xyz.key |
并设置续期后的:
1 | systemctl reload nginx |
8. 修改 Nginx 后必须执行什么
先:
1 | nginx -t |
只有显示语法检查成功后,才能:
1 | systemctl reload nginx |
9. 443 节点订阅里不能出现 127.0.0.1
127.0.0.1 只是 Xray 在服务器内部的监听地址。
客户端仍然必须连接:
1 | 服务器公网 IP / 公网域名 |
如果 3x-ui 生成的分享链接或 Clash/Mihomo 订阅错误地出现 127.0.0.1,需要在 3x-ui 的 Host / 外部分享地址设置中指定公网 IP 或公网域名。
10. Komari / OpenList / PanSou 是否能通过当前配置获取真实访客 IP
本教程使用的是最简化的:
1 | Nginx stream |
stream 到内部 HTTPS 的连接通常表现为本机连接,因此本教程不以透传网站访客真实源 IP 为目标。
如果后端业务必须精确获得原始客户端 IP,需要另外设计 PROXY Protocol 或其他四层转发方式,不能在当前公共 stream server 上简单全局开启 PROXY Protocol,否则会同时影响 Xray 后端。
十四、以后新增其他网站的标准流程
假设新增:
1 | new.10181128.xyz |
后端服务:
1 | 127.0.0.1:8080 |
标准流程:
DNS 将
new.10181128.xyz解析到服务器公网 IP。为域名申请 HTTPS 证书。
将证书安装到
/etc/nginx/ssl/。给网站分配新的内部 HTTPS 端口,例如
127.0.0.1:31305。创建新的 Nginx HTTPS
server {},反代到127.0.0.1:8080。在
/etc/nginx/stream.d/443.conf中增加:1
2
3
4
5
6
7
8map $ssl_preread_server_name $backend_443 {
komari.10181128.xyz 127.0.0.1:31302;
alist.10181128.xyz 127.0.0.1:31303;
pansou.10181128.xyz 127.0.0.1:31304;
new.10181128.xyz 127.0.0.1:31305;
default 127.0.0.1:443;
}检查:
1
nginx -t
重新加载:
1
systemctl reload nginx
测试:
1
https://new.10181128.xyz
新增网站不需要修改 3x-ui 的 443 Xray 入站。
十五、核心原则
旧 v2ray-agent fallback:
1 | 公网 443 |
本教程 3x-ui + Nginx stream:
1 | 公网 443 |
核心原则:
1 | 公网 443 永远给 Nginx stream |
只要最终端口状态满足:
1 | 公网IP:443 -> nginx |
并且 Komari、OpenList、PanSou 网站域名以及 Reality / TLS 节点均可正常访问,即说明 3x-ui 与多个网站共用 443 端口配置成功。
站点与 Xray 共用 443 反向代理 —— Nginx Stream
https://10181128.xyz/2026/08/27/站点与Xray共用443反向代理-Nginx Stream/

