前言
这次记录的是一套代理服务端配置的调整过程:最开始尝试用 Nginx 做前置转发 Xray XHTTP,但 H3/UDP 下行经过 Nginx 后速度明显偏低;同样的 Xray 直连 H3 诊断入口可以跑满,所以瓶颈基本可以定位在前置层。最后把公网入口改成 Envoy,由 Envoy 接管 TCP/443 的 HTTPS/H2 和 UDP/443 的 HTTP/3,再把 XHTTP 流量转发给本机 Xray,把普通网页流量转发给本机 Nginx 伪装站。
简单对比一下当时的测试结果:
| 方案 | 下行表现 | 说明 |
|---|---|---|
| XHTTP H2 上行 + H2 下行 | 约 334-339 Mbps | 不走 H3 下行时基本正常 |
| XHTTP H2 上行 + H3 下行,经 Nginx 前置 | 约 7-15 Mbps | 主要瓶颈出现在 Nginx 前置转发 H3 |
| XHTTP H3 直连 Xray 9443 诊断口 | 约 367 Mbps | 说明 Xray 自身和线路并不是主要瓶颈 |
| Caddy 前置 H3 | 约 41 Mbps | 比 Nginx 好,但仍不理想 |
| Envoy 前置 H3 | 作为最终方案 | 用 Envoy 替代 Nginx 做公网 H3 入口 |
为了避免泄露真实信息,本文里的域名、UUID、密码、统计密钥、XHTTP 路径 token 都已经脱敏。直接复制前需要把占位符替换成自己的值。
当前架构
调整后的架构里,Nginx 不再作为公网 443 前置,只保留为本机静态伪装站后端;公网 TCP/80、TCP/443、UDP/443 都交给 Envoy。
公网入口:
| 端口 | 协议 | 服务 | 作用 |
|---|---|---|---|
| TCP/80 | HTTP | Envoy | HTTP 跳转 HTTPS,ACME challenge 转发到 Nginx |
| TCP/443 | HTTPS/H2 | Envoy | XHTTP 上行、普通 HTTPS 伪装站 |
| UDP/443 | HTTP/3 | Envoy | XHTTP H3 下行、普通 H3 入口 |
| UDP/9443 | Xray | XHTTP/H3 诊断入口 | 绕过前置的测试入口,不作为常规使用 |
本机后端:
| 地址 | 服务 | 作用 |
|---|---|---|
| 127.0.0.1:10000 | Xray | Envoy 转发过来的 XHTTP 后端 |
| 127.0.0.1:10085 | Xray API | stats、在线用户、限额脚本 |
| 127.0.0.1:18080 | Nginx | 伪装站和 ACME challenge |
| 127.0.0.1:9901 | Envoy admin | Envoy 本机管理接口 |
软件版本:
1 | Xray 26.3.27 |
Xray 配置
配置文件路径:
1 | /usr/local/etc/xray/config.json |
这里 Xray 只监听本机 XHTTP 后端和 API,TLS/H2/H3 由 Envoy 在公网侧处理。diag-xhttp-h3-direct 是直连 H3 诊断入口,用来判断瓶颈是否来自前置代理。
1 | { |
这里有两个关键点:
policy里开启了用户上行、下行和在线统计,所以xray api statsquery、statsonline、statsonlineiplist可以正常使用。- 路由里拒绝了中国 IP、中国域名、私网地址和 BitTorrent,避免节点被拿来访问国内或跑 BT。
Envoy 配置
配置文件路径:
1 | /etc/envoy/envoy.yaml |
Envoy 的作用是统一接管公网 TCP/80、TCP/443、UDP/443。TCP/443 提供 H2,UDP/443 提供 H3;命中 XHTTP 随机路径的请求转给 Xray,其他请求转给 Nginx 伪装站。
之所以让 Envoy 接管公网入口,是因为 Nginx 做 H3/UDP 前置时下行速度明显掉到十几 Mbps,和 Xray 直连 H3 的三百多 Mbps 不在一个量级。Envoy 的 HTTP/3 支持更适合这个场景,也方便同时保留 HTTP 跳转、ACME challenge 和普通伪装站路由。
1 | admin: |
当时测试过几种前置方式,H3 经过 Nginx Stream 时下行明显掉速,Caddy 有改善但仍不理想,最后切到 Envoy 做 HTTP/3 入口。实际环境里建议保留一个 Xray 直连 H3 诊断端口,用来判断是 Xray 自身、前置代理还是网络路径造成的瓶颈。
Nginx 伪装站配置
Nginx 不再监听公网 80/443,也不再承担 H3/UDP 前置转发。它只监听本机端口,作为 Envoy 的静态伪装站后端。这样既保留 Nginx 处理静态文件的简单性,又避开了它在这次 H3 转发测试中的速度瓶颈。
主配置:
1 | user nginx; |
伪装站配置:
1 | server { |
默认站也改成本机监听,避免和 Envoy 的公网端口冲突:
1 | server { |
Caddy 备用配置
当前 Caddy 是 disabled,不参与公网入口。机器上仍保留过一版 Caddyfile,方便后续需要时切回 Caddy 前置。这里同样做了脱敏:
1 | { |
证书部署 Hook
证书由 Let’s Encrypt 生成后,通过 deploy hook 同步到 Envoy、Xray 等服务目录,并重载或重启相关服务。
1 |
|
虽然当前入口已经换成 Envoy,hook 里仍然保留了 Caddy 证书同步和 reload 逻辑,是为了以后切换前置时少改一点东西。当前 Caddy 是 disabled,不参与公网入口。
证书私钥文件、证书链文件、历史备份配置和临时诊断客户端配置不适合原样贴到博客里。本文只记录路径和引用方式,不包含任何 PEM 私钥内容。
systemd 服务
Xray:
1 | [Unit] |
Envoy:
1 | [Unit] |
Xray 流量统计和 50GB 限额
Xray 通过 API 统计每个用户的上下行,并用 systemd timer 每分钟运行一次限额脚本。50GB 用户超过累计流量后,通过 Xray API 删除对应用户。
/etc/systemd/system/xray-traffic-limit.service:
1 | [Unit] |
/etc/systemd/system/xray-traffic-limit.timer:
1 | [Unit] |
限额脚本:
1 |
|
注意:如果 Xray 的入口 tag 改了,限额脚本里的 -tag=reality-in 也要同步修改,否则删除用户不会命中正确 inbound。当前配置里公网 XHTTP 实际走的是 xhttp-caddy-backend,如果需要同时封禁所有入口,脚本里应对相关 inbound tag 都执行一次 rmu。
分享链接模板
XHTTP 上下行分离的分享链接大致如下。这里把关键值都替换成了占位符:
1 | vless://<UUID>@<UPLOAD-DOMAIN>:443?encryption=none&security=tls&sni=<UPLOAD-DOMAIN>&fp=chrome&type=xhttp&host=<UPLOAD-DOMAIN>&path=%2Fapi%2Fv1%2F<XHTTP-PATH-TOKEN>&mode=stream-up&alpn=h2&extra=<URL-ENCODED-EXTRA>#TLS-XHTTP-H2up-H2down |
extra 里可以放 padding、xmux 和 downloadSettings。例如下载侧使用另一个域名:
1 | { |
验证命令
看服务状态:
1 | systemctl status xray envoy nginx --no-pager |
看监听端口:
1 | ss -lntup | grep -E '(:80|:443|:9443|:10000|:10085|:18080|:9901)' |
验证 Envoy 配置:
1 | envoy --mode validate -c /etc/envoy/envoy.yaml |
看 Envoy H3 统计:
1 | curl -s http://127.0.0.1:9901/stats | grep http3 |
看 Xray 用户统计:
1 | xray api statsquery --server=127.0.0.1:10085 -pattern 'user>>>client-unlimited@local>>>traffic>>>' |
结论
这套配置的核心是把入口层和代理层分开:Envoy 负责公网 HTTPS/H2/H3 和伪装站转发,Xray 专注处理 XHTTP,Nginx 只做本机静态站。改成 Envoy 的直接原因,是 Nginx 作为 H3 前置时下行速度明显偏低,而 Xray 直连 H3 诊断口能跑满,说明继续调 Xray 参数意义不大,应该替换前置层。
实际测试中,XHTTP H2/H2 可以跑满链路,H3 下行是否高性能和前置实现关系很大。Nginx Stream 转发 H3 时容易成为瓶颈,Caddy 有改善,Envoy 更适合做这类 HTTP/3 入口。如果遇到速度异常,建议保留一个 Xray 直连 H3 诊断入口,先确认 Xray 自身在当前线路下能否跑满。
说些什么吧!