9.7 KiB
Nginx + Xray(Reliability)多域名共用443端口完美解决方案
为了更好的伪装,且本身有两个网站要使用,所以就弄了这么一个东西,最终就是两个网站和Xray都使用443端口,流量监测的时候代理的流量被伪装成了正常的TSL,没有问题,这个是基础功能。如果主动探测,代理域名,不是客户端访问引导到正常更新使用的博客上。 在这篇文章前,使用的Xray在前,使用Xray的回落机制+分流实现。不过会该方案有严重的串站问题。最后定了下面的方案,Nginx在前通过串流,原封不动的将代理域名的信息转给Xray。
一、需求背景与最终架构
1.1 原始需求
一台服务器(Debian 12 + Nginx 1.22.1 + PHP 8.2) 三个域名都使用443端口: 网站A域名:Discuz论坛(HTTPS) 网站B域名:WordPress博客(HTTPS) 代理域名:XRay代理(REALITY协议) 探测代理域名时能看到真实的博客内容(回落机制) 绝对不串站
1.2 最终架构(Nginx在前 + stream分流)
用户访问 ↓ 443端口 → Nginx(stream模块,读SNI不解密) ├─ SNI = 网站A域名 → 127.0.0.1:4431 ├─ SNI = 网站B域名 → 127.0.0.1:4432 └─ SNI = 代理域名 → 127.0.0.1:8443 ↓ ↓ ↓ Nginx http(4431) Nginx http(4432) Xray(8443) 处理论坛(HTTPS) 处理博客(HTTPS) 处理代理 回落指向博客端口(4432)
二、配置步骤详解
2.1 准备工作:SSL证书(Let's Encrypt)
#安装Certbot apt update apt install certbot python3-certbot-nginx -y
#申请证书(包含三个域名) certbot --nginx -d 网站A域名 -d 网站B域名 -d 代理域名
#注意:如果已有其中一个域名的证书,选择 Expand 扩展域名 #证书路径:/etc/letsencrypt/live/代理域名/
2.2 备份原有配置(可选)
cp /etc/nginx/conf.d/网站A.conf /etc/nginx/conf.d/网站A.conf.bak cp /etc/nginx/conf.d/网站B.conf /etc/nginx/conf.d/网站B.conf.bak cp /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.bak cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
2.3 修改Nginx主配置(添加stream模块)
编辑 /etc/nginx/nginx.conf,在文件最顶部(events块之前)添加:
stream {
#根据SNI域名转发到不同后端
map $ssl_preread_server_name $backend {
网站A域名 127.0.0.1:4431;
网站B域名 127.0.0.1:4432;
代理域名 127.0.0.1:8443;
default 127.0.0.1:4432; #默认看博客
}
server {
listen 443 reuseport;
listen [::]:443 reuseport;
ssl_preread on;
proxy_pass $backend;
#超时设置
proxy_connect_timeout 30s;
proxy_timeout 30s;
}
}
#下面是原有的 events { ... } 和 http { ... }
events {
worker_connections 768;
#...
}
2.4 配置论坛(网站A)
编辑 /etc/nginx/conf.d/网站A.conf:
server {
listen 127.0.0.1:4431 ssl;
server_name 网站A域名;
#SSL证书
ssl_certificate /etc/letsencrypt/live/代理域名/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/代理域名/privkey.pem;
#SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
root /var/www/网站A;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param HTTPS on;
}
location ~ /\.ht {
deny all;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
2.5 配置博客(网站B)
编辑 /etc/nginx/conf.d/网站B.conf:
server {
listen 127.0.0.1:4432 ssl;
server_name 网站B域名;
#SSL证书(和论坛用同一个)
ssl_certificate /etc/letsencrypt/live/代理域名/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/代理域名/privkey.pem;
#SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
root /var/www/wordpress;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param HTTPS on;
}
location ~ /\.ht {
deny all;
}
client_max_body_size 128M;
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
2.6 配置XRay
编辑 /usr/local/etc/xray/config.json:
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"port": 8443,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "你的uuid-1",
"flow": "xtls-rprx-vision"
},
{
"id": "你的uuid-2",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": []
},
"streamSettings": {
"network": "raw",
"security": "reality",
"realitySettings": {
"dest": "127.0.0.1:4432", // 回落指向博客端口
"serverNames": [
"代理域名"
],
"privateKey": "你的私钥",
"shortIds": [
"你的shortId-1",
"你的shortId-2"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
2.7 重载服务
nginx -t && systemctl reload nginx xray -test -config /usr/local/etc/xray/config.json systemctl restart xray
三、踩坑记录与解决方案
坑1:证书申请时提示找不到代理域名的server_name
现象: text Could not automatically find a matching server block for 代理域名 原因:代理域名由XRay处理,Nginx中没有对应的server块 解决方案: bash #临时创建一个代理域名的Nginx配置
cat > /etc/nginx/conf.d/代理域名.temp.conf << EOF
server {
listen 80;
server_name 代理域名;
root /var/www/html;
}
EOF
nginx -t && systemctl reload nginx certbot install --cert-name 代理域名 rm /etc/nginx/conf.d/代理域名.temp.conf
坑2:XRay回落配置错误导致循环
现象:curl测试代理域名时报错 SSL_ERROR_SYSCALL 原因:XRay配置中dest写成了域名网站B域名:443,导致流量循环 解决方案:改为直接指向博客的本地端口 json "dest": "127.0.0.1:4432"
坑3:浏览器测试时串站(先打开论坛,后面全变论坛)
现象:同一个浏览器中,先访问网站A,再开新标签页访问网站B,显示论坛内容 原因:HTTP/2的连接合并(coalescing)特性,三个域名共用同一IP和证书,浏览器复用连接 解决方案:在网站配置中禁用HTTP/2 nginx #将 listen 127.0.0.1:4431 ssl http2; 改为 listen 127.0.0.1:4431 ssl; 验证:禁用后感觉不到速度差异,问题彻底解决
坑4:论坛友情链接跳转也串站
现象:从论坛点击友情链接到博客,显示论坛内容 原因:同坑3,同一标签页内跳转复用了连接 解决方案:同坑3,禁用HTTP/2后解决
坑5:reuseport参数导致分流异常(偶发)
现象:偶尔出现分流错误,重启Nginx后恢复 原因:某些内核版本中reuseport与ssl_preread共用可能异常 解决方案:去掉reuseport参数(本案例最终保留,但遇到问题时可去掉)
四、验证命令汇总
4.1 验证Nginx配置
nginx -t nginx -T | grep -A 20 -B 5 "stream {"
4.2 验证stream分流
#测试论坛(每次新建连接) curl -k --no-keepalive https://网站A域名 --resolve 网站A域名:443:127.0.0.1 | grep -o ""
#测试博客 curl -k --no-keepalive https://网站B域名 --resolve 网站B域名:443:127.0.0.1 | grep -o ""
#测试代理域名(应返回博客内容) curl -k --no-keepalive https://代理域名 --resolve 代理域名:443:127.0.0.1 | grep -o ""
4.3 验证XRay
systemctl status xray ss -tlnp | grep 8443 xray -test -config /usr/local/etc/xray/config.json
4.4 验证证书自动续期
bash systemctl list-timers | grep certbot certbot renew --dry-run
五、客户端配置(XRay)
##5.1 连接信息 参数 值 地址 代理域名 端口 443 协议 VLESS UUID 你的uuid Flow xtls-rprx-vision 加密 none 安全 reality serverName 代理域名
publicKey 你的公钥 shortId 你的shortId dest 网站B域名:443(客户端不需要配置,这是服务端回落目标)
六、最终状态确认
组件 状态 验证方式 论坛 HTTPS ✅ 正常 浏览器访问 https://网站A域名 博客 HTTPS ✅ 正常 浏览器访问 https://网站B域名 代理域名回落 ✅ 正常 浏览器访问 https://代理域名 看到博客 XRay代理 ✅ 正常 客户端连接测试 证书续期 ✅ 自动 systemctl list-timers | grep certbot 串站问题 ✅ 解决 不同浏览器同时访问三个域名均正确