本文讲解 Xray 终止 TLS 后的 SNI fallback;需要保持 TLS 握手不变的方案见 Nginx stream 分流。
Xray VLESS + TLS 可以占用 443,并把普通 HTTPS 请求按 SNI 回落到本机不同网站。TLS 在 Xray 中终止,所以后端收到的是解密后的协议流量;xver: 1 表示在流量前增加 PROXY protocol v1,并不表示后端再次收到 TLS。
示例使用自己控制的 site.example.com 和 dns.example.com,两者指向同一服务器。前者提供网站,后者只开放 DoH 的 /dns-query;AdGuard Home 管理界面留在内部访问路径。证书覆盖这两个名称,可参考 ACME 泛域名证书。
Xray 入站
下面是已有 Xray 配置中的入站片段。替换 UUID、证书路径和域名,保留自己的出站与路由;示例只协商 HTTP/1.1,避免把 h2 流量错误送给只接受 HTTP/1.1 的端口。
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{ "id": "00000000-0000-4000-8000-000000000001" }
],
"decryption": "none",
"fallbacks": [
{ "name": "dns.example.com", "dest": "127.0.0.1:8081", "xver": 1 },
{ "dest": "127.0.0.1:8080", "xver": 1 }
]
},
"streamSettings": {
"method": "raw",
"security": "tls",
"tlsSettings": {
"alpn": ["http/1.1"],
"certificates": [
{
"certificateFile": "/etc/ssl/xray/fullchain.pem",
"keyFile": "/etc/ssl/xray/private.key"
}
]
}
}
}
]
}
当前文档使用 method: raw;旧版本常使用 network: tcp/raw。按安装版本核对传输字段,不要直接把新配置写进旧脚本生成的文件。UUID 必须重新生成,上述固定值只能用于展示结构。若服务通过 IPv6 提供入口,还要检查实际监听与防火墙,不能假设 0.0.0.0 会同时接收 IPv6。
这里的 SNI 匹配负责选择回落目标。ALPN 的优先级由 TLS 配置的 alpn 与客户端协商决定,不是靠交换 fallback 数组里的 h2 和 http/1.1 条目实现。需要 h2 时另外准备支持明文 HTTP/2(h2c)的本机后端,再添加匹配的 ALPN 回落规则。VLESS、Fallback、TLS
本机 Nginx 接收回落
Nginx 必须同时启用 HTTP realip 模块、在 listen 中接收 PROXY protocol,并只信任实际转发者。下面两个端口只绑定 loopback,不能额外暴露到公网。
server {
listen 127.0.0.1:8080 proxy_protocol;
server_name site.example.com;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
root /srv/www/site;
index index.html;
location / { try_files $uri $uri/ =404; }
}
server {
listen 127.0.0.1:8081 proxy_protocol;
server_name dns.example.com;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
location = /dns-query {
# 替换为自己的固定客户端公网地址;动态客户端需另选认证方式。
allow 192.0.2.10;
deny all;
proxy_pass https://127.0.0.1:8443;
proxy_set_header Host dns.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_ssl_server_name on;
proxy_ssl_name dns.example.com;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
}
location / { return 404; }
}
假设 AdGuard Home 的 HTTPS/DoH 已监听 127.0.0.1:8443,证书对 dns.example.com 有效且链能被所列 CA 文件验证;若使用自签证书,改为信任自己的 CA 并保持名称校验。CA bundle 路径随系统不同,不能通过 proxy_ssl_verify off 绕过配置问题。192.0.2.10 是文档地址,必须替换,否则真实客户端会被拒绝。
访问控制使用 realip 还原后的客户端地址。直接向后端发送普通 HTTP 会因为缺少 PROXY 前缀失败;公网用户无法直接访问 loopback 后端,也不能自行提供可信 PROXY 地址。只代理 /dns-query 可以避免把 AdGuard Home 登录、设置和管理 API 一起暴露;需要管理时通过 VPN 或内部入口。
可选:代理自己的 HTTPS 网站
如果网站不在本机静态目录,将第一个 server 的 location 改为自己的上游。域名、Host、SNI 与证书名称需要对应,开启上游证书校验:
location / {
proxy_pass https://origin.example.com;
proxy_set_header Host origin.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_ssl_server_name on;
proxy_ssl_name origin.example.com;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
}
应用应配置公开域名和可信代理地址,重定向、Cookie、CSP 与绝对 URL 需要按应用处理,不能靠全局 sub_filter 可靠地改写。HSTS preload 也不是通用反代配置,确认整个域名及子域长期支持 HTTPS 后才考虑它。Nginx HTTPS 上游校验、realip
应用配置前后检查
先用实际的 Xray 二进制执行配置检查,再以实际 Nginx 的 -t 检查配置,通过后重载对应服务。例如 xray-agent 项目与手工安装可能使用不同的配置组织,/etc/nginx/conf.d/alone.conf 不是所有部署通用的固定路径。
从外网用真实证书访问两个域名,分别检查网站、DoH GET/POST、未授权请求拒绝、管理路径 404 与访问日志中的来源地址。测试通过的范围必须包含这整条链路;单独确认 Nginx 语法正确不能证明 Xray 回落和 AdGuard Home 的证书/访问控制已经工作。
评论区