本文最后更新于 2026 年 4 月 27 日
本文以 Debian 13 为例,介绍如何搭建 Xray-core 的 VLESS + XHTTP 服务端,使用 Nginx 反代,并通过 Cloudflare 橙色云隐藏源站 IP。本文同样适用于 Ubuntu 24.04 及以上系统。
注:请先参照 Debian & Ubuntu 服务器的初始化配置 一文对服务器进行各种必要的配置。本文以 sammy 用户为例,并默认已按初始化配置文章对服务器进行了配置。
本方案采用:
1 | 客户端 Xray |
本方案特点:
- XHTTP 使用 H2/gRPC-like 流量形态,适合 Cloudflare 橙色云直回源
- Nginx 负责 TLS、HTTP/2、伪装站和路径分流
- Xray 只监听本地回环地址,不直接暴露公网
- VPS 443 端口只允许 Cloudflare IP 访问
- 客户端启用 ECH、uTLS Chrome、XHTTP padding obfs
- 证书使用 acme.sh + Cloudflare DNS-01 自动续期
与 Cloudflare Tunnel 方案相比,本方案性能更直接,XHTTP 兼容性更好;代价是源站必须开放 443 给 Cloudflare,并且需要管理源站证书。
准备工作
所需资源
- 一台公网 VPS
- 一个已托管到 Cloudflare 的域名
- 一个子域名,例如
cdn.example.com - 一套静态网页,用作伪装站
下文假设:
| 项目 | 示例值 |
|---|---|
| 用户名 | sammy |
| 域名 | cdn.example.com |
| Xray 本地端口 | 127.0.0.1:10000 |
| 伪装站目录 | /var/www/camouflage |
| XHTTP 路径 | /a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 |
| Header Token | f9e2c4a7b1d8e6c3a0f5b2d9e8c1a4b7d6e0f3a9c2b5d1e8 |
生成 UUID:
1 | cat /proc/sys/kernel/random/uuid |
生成随机路径:
1 | openssl rand -hex 16 |
生成 Header Token:
1 | openssl rand -hex 24 |
Cloudflare 设置
DNS
添加 DNS 记录:
| 类型 | 名称 | 内容 | 代理状态 |
|---|---|---|---|
| A | cdn | VPS IPv4 | Proxied |
| AAAA | cdn | VPS IPv6 | Proxied,若有 IPv6 |
必须是橙色云。
SSL/TLS 与 Network
进入 Cloudflare 域名 Dashboard:
| 位置 | 设置 |
|---|---|
| SSL/TLS → Overview | Full (strict) |
| SSL/TLS → Edge Certificates | TLS 1.3 On |
| SSL/TLS → Edge Certificates | Minimum TLS Version: TLS 1.3 |
| SSL/TLS → Edge Certificates | ECH Enabled |
| Network | HTTP/2 On |
| Network | gRPC On |
Cloudflare gRPC 要求源站监听 443、支持 TLS、支持 HTTP/2,并通过 ALPN 宣告 HTTP/2。
Cache Rules
为 XHTTP 路径创建缓存绕过规则:
1 | When: |
WAF Skip Rule
创建 WAF Custom Rule:
1 | Expression: |
建议跳过:
- WAF Managed Rules
- Rate Limiting Rules
- Super Bot Fight Mode Rules
- Browser Integrity Check
VPS 初始化
安装基本工具:
1 | sudo apt update |
服务器防火墙
只允许 Cloudflare IP 访问 443。本文假设初始化文章已配置并启用 UFW,且 SSH 已放行;本节只新增 Cloudflare 到 443 的规则。
创建脚本目录:
1 | sudo mkdir -p /root/scripts/ufw |
添加 Cloudflare 规则:
1 | sudo vim /root/scripts/ufw/add-cloudflare.sh |
1 |
|
更新 Cloudflare 规则:
1 | sudo vim /root/scripts/ufw/update-cloudflare.sh |
1 |
|
执行:
1 | sudo chmod +x /root/scripts/ufw/*.sh |
添加定时更新:
1 | sudo crontab -e |
加入:
1 | MAILTO="" |
安装 Nginx
1 | sudo apt update |
安装 Xray-core
1 | sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install |
检查版本:
1 | xray version |
建议使用 v26.3.27 或更新版本。
申请证书
本文使用 acme.sh + Cloudflare DNS-01。这样不需要开放 80,也不受橙色云影响。
acme.sh 可以用普通用户运行,但官方更推荐 root。本文按 root 安装,省去证书目录权限和 sudo reload 的额外配置。
切换到 root
1 | sudo -i |
后续本节命令均在 root shell 中执行。
安装 acme.sh
1 | curl https://get.acme.sh | sh -s [email protected] |
如需固定使用 Let’s Encrypt,可执行:
1 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt |
不执行也可以,acme.sh 会使用自身默认 CA。
准备 Cloudflare API Token
创建 Cloudflare API Token,建议使用以下设置:
- Permissions:Zone → DNS → Edit
- Zone Resources:Include → Specific zone → example.com
- Client IP Address Filtering:Is in,分别添加服务器的 ipv4 和 ipv6 稳定出口地址
设置 token 和 zone ID:
1 | export CF_Token="你的 Cloudflare API Token" |
签发并安装证书
准备证书目录:
1 | mkdir -p /etc/nginx/ssl |
签发 ECC 证书:
1 | ~/.acme.sh/acme.sh --issue --dns dns_cf -d cdn.example.com --keylength ec-256 |
安装到 Nginx 使用的路径:
1 | ~/.acme.sh/acme.sh --install-cert -d cdn.example.com --ecc \ |
检查:
1 | ls -l /etc/nginx/ssl/ |
acme.sh 会在 root 的 crontab 中写入自动续期任务。
退出 root shell:
1 | exit |
伪装站
创建目录:
1 | sudo mkdir -p /var/www/camouflage |
自行准备并放入:
1 | /var/www/camouflage/index.html |
推荐使用 Hugo、Hexo、Astro、VitePress 等生成的真实静态站。不要使用 Nginx 默认欢迎页或空白页。
Nginx 配置
编辑:
1 | sudo vim /etc/nginx/sites-available/cdn.example.com |
写入:
1 | server { |
第一个 default_server 用于拒绝错误 SNI、直接访问 IP、未带 SNI 的 HTTPS 探测。无需再准备自签默认证书。
启用站点:
1 | sudo ln -sf /etc/nginx/sites-available/cdn.example.com /etc/nginx/sites-enabled/cdn.example.com |
Xray 服务端配置
编辑:
1 | sudo vim /usr/local/etc/xray/config.json |
写入,注意替换 UUID、域名、路径:
1 | { |
检查并启动:
1 | sudo xray run -test -config /usr/local/etc/xray/config.json |
检查监听:
1 | sudo ss -tlnp | grep 10000 |
应看到:
1 | 127.0.0.1:10000 |
客户端配置
以下为 Xray 客户端示例。注意替换 UUID、域名、路径和 Header Token。
1 | { |
ECH 策略
隐蔽优先,默认推荐:
1 | "echForceQuery": "full" |
full 表示拿不到有效 ECHConfig 就不连接,避免回退到明文 SNI。
可用优先,排障时使用:
1 | "echForceQuery": "half" |
half 表示查询失败时本次不用 ECH,但后续继续尝试。
使用 Cloudflare 优选 IP
如果使用优选 IP,只改:
1 | "address": "104.16.132.229" |
以下两项保持真实域名:
1 | "serverName": "cdn.example.com" |
1 | "host": "cdn.example.com" |
验证
服务状态
1 | sudo systemctl status nginx |
应看到:
1 | 0.0.0.0:443 |
浏览器访问
访问:
1 | https://cdn.example.com |
应显示伪装站首页。
访问:
1 | https://cdn.example.com/任意不存在路径 |
应显示自定义 404。
访问隐藏路径:
1 | https://cdn.example.com/a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 |
也应显示 404,因为浏览器没有 X-Access-Token。
直接访问源站 IP 或错误域名,应在 TLS 握手阶段被拒绝,不应返回站点证书或伪装站内容。
检查 ECHConfig
在客户端本地执行:
1 | dig cdn.example.com HTTPS @1.1.1.1 |
返回中应包含:
1 | ech=... |
常见问题
Cloudflare 返回 403
检查:
- Cloudflare gRPC 是否开启
- DNS 是否为橙色云
- SSL/TLS 是否为 Full 或 Full strict
- Nginx 是否监听 443
- Nginx 是否启用
http2 on;
Cloudflare 返回 525 / 526
检查:
- 证书是否存在
- 证书域名是否匹配
cdn.example.com - 证书是否过期
- Cloudflare SSL/TLS 是否为 Full strict
浏览器正常,客户端不通
检查:
- UUID 是否一致
- 路径是否一致
- Header Token 是否一致
- 客户端
serverName是否为真实域名 - 客户端
host是否为真实域名 - Xray 是否监听
127.0.0.1:10000 - Nginx 是否使用
grpc_pass grpc://127.0.0.1:10000
mode: auto 不稳定
客户端改为:
1 | "mode": "packet-up" |
服务端保持:
1 | "mode": "auto" |
ECH 导致连接失败
如果当前是:
1 | "echForceQuery": "full" |
先改成:
1 | "echForceQuery": "half" |
如果 half 能连接,说明 ECHConfig 查询或本地 DNS 路径不稳定。
v26 padding 字段报错
升级 Xray-core。若客户端暂不支持,删除以下字段:
1 | "xPaddingObfsMode": true, |
只保留:
1 | "xPaddingBytes": "100-1000" |
客户端和服务端要保持一致。
更新维护
更新系统组件
1 | sudo apt update |
更新 Xray
1 | sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install |
手动续期测试
1 | sudo /root/.acme.sh/acme.sh --cron --home /root/.acme.sh --force |
轮换 UUID、路径和 Token
建议 3 到 6 个月轮换一次:
1 | xray uuid |
同步修改:
- Xray 服务端 UUID
- Xray 服务端 path
- Nginx location path
- Nginx Header Token
- 客户端 UUID
- 客户端 path
- 客户端 Header Token
- Cloudflare Cache Rule
- Cloudflare WAF Skip Rule
最终配置摘要
| 项目 | 推荐值 |
|---|---|
| 架构 | Cloudflare 橙色云 → Nginx → Xray |
| DNS | Proxied |
| Cloudflare SSL/TLS | Full strict |
| Cloudflare gRPC | On |
| 源站端口 | 443 |
| 源站证书 | acme.sh DNS-01 自动续期 |
| Nginx HTTP/2 | http2 on; |
| 未知 SNI / 直接 IP | ssl_reject_handshake on; |
| Nginx 到 Xray | grpc_pass grpc://127.0.0.1:10000 |
| Xray 监听 | 127.0.0.1:10000 |
| Xray 入站 | VLESS + XHTTP |
| 服务端 TLS | Nginx 处理,Xray security: none |
| 客户端 TLS | security: tls |
| 客户端 ALPN | h2 |
| 客户端 fingerprint | chrome |
| XHTTP mode | auto |
| fallback mode | packet-up |
| ECH 默认 | full |
| ECH 排障 | half |
| padding | xPaddingBytes + v26 obfs tokenish |
| 伪装站目录 | /var/www/camouflage |