开启 3 天免费试用
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。


VLESS 套 CDN,是在客户端与你自己控制的 Ubuntu VPS 之间加一层 CDN 边缘节点:客户端连接边缘上的自有域名,CDN 只把一个秘密路径转发回源站,Xray 只在本机回环地址上接收。本文使用 Xray v26.3.27、源站 Nginx 反向代理,并以 Cloudflare 作为 CDN 示例,传输方式在 WebSocket 与 XHTTP 中二选一。[1]
关键要点
- 动手前先读 CDN 当前条款;隧道能用,不代表这种用法被允许。
- 回源使用 Cloudflare Full (strict) 这类严格 TLS 模式,不用跳过证书校验的模式。
- Xray 只监听
127.0.0.1,每种传输只由 Nginx 转发一个秘密路径。- 套 CDN 时 XHTTP
packet-up是稳妥选择,WebSocket 更简单也更老。- 把“客户端连上了”和“流量走了 CDN”分开验证:分别测试直连源站、错误路径与错误 UUID 被拒。
本文依据文末官方来源整理,未完成完整端到端实测。版本号只说明所依据的文档,不是作者实测环境。开始前,先按自建规划与恢复清单明确归属、访问权限和恢复方式。
只在你拥有或有权管理的 VPS 和域名上操作。你需要不依赖代理的控制台访问、按已核验 known_hosts 严格校验主机密钥的 SSH,以及现有 Nginx、防火墙和 Xray 文件的备份。不要借用他人域名、免费子域名服务或第三方 Worker 来承载自己的入口。
CDN 会改变谁能看到并终结你的流量。边缘节点先解密客户端的 TLS,再向源站建立第二条 TLS 连接,因此 CDN 运营方会在中间经手你的代理流。如果你只需要稳定的日常出口,不想自己维护证书、Nginx 和 Xray,先评估托管 VPN 是否更省事,再决定是否多加一个环节。边缘与源站的一般关系,可参考 CDN 如何位于你和网站之间。
Cloudflare 服务专属条款保留这样的权利:在未购买相应付费服务的情况下,若用 CDN 提供视频或不成比例的大文件,可以停用或限制其 CDN 使用。[2] 承载流媒体或大量下载的代理可能落入这一情形。请阅读当前条款和你所用套餐的限制;如果需要一条不受 CDN 政策影响的路径,保留一个直连入口,例如 VLESS REALITY 服务器。
本文的任何步骤都不能让线路“不会被封”。CDN 可能重启边缘服务器、执行空闲超时或调整功能;Cloudflare 也写明,发布更新时可能中断已打开的 WebSocket 连接。[3]
两种传输都把 VLESS 装在 HTTP 里,因此能代理 HTTP 的 CDN 都可以转发。区别在于数据流的组织方式,以及 CDN 需要放行什么。
| 问题 | VLESS WebSocket TLS 配置 | VLESS XHTTP 套 CDN(packet-up) |
|---|---|---|
| 数据如何传输 | 一条升级后的 HTTP/1.1 连接 | 上行拆成编号 POST 请求,下行是流式 GET |
| 对 CDN 的要求 | 该区域开启 WebSockets | 普通 HTTP 代理即可,不需要协议升级 |
| Project X 的建议 | 文档建议改用 XHTTP,因为 WebSocket 的 ALPN 是 http/1.1 | packet-up 被描述为在 CDN 和反代后兼容性最强的模式 |
| 源站反代要求 | 传递 Upgrade 与 Connection 头 | 请求体和响应体都不缓冲 |
| 主要取舍 | 简单,客户端支持广泛 | 较新,客户端和服务端内核都必须支持 |
Project X 的 WebSocket 页面建议改用 XHTTP,以避开 WebSocket 明显的 http/1.1 ALPN 特征。[4] XHTTP 传输条目指向项目的 XHTTP 讨论帖;帖中建议在 CDN 或反向代理不放行其它模式时选择 packet-up,并指出经 Cloudflare 使用 stream-up 需要开启 gRPC 支持。[5][6] 本文把 XHTTP 固定为 packet-up,让源站保持普通的 HTTP/1.1 反代。如果你已经有直连的 XHTTP 入口,请让它与这个 CDN 入口保持独立。
创建一条指向 VPS 的 DNS 记录,例如 proxy.example.com,并设为经 CDN 代理。在 Cloudflare 中把该区域的 SSL/TLS 模式设为 Full (strict):边缘节点会校验源站证书,证书可以来自公共 CA,也可以来自 Cloudflare Origin CA。[7] 不要使用 Flexible 或 Full,前者回源不加密,后者接受无效证书。
如果选择 WebSocket,在区域的 Network 设置里开启 WebSockets。[3] 把源站证书和私钥放在 /etc/ssl/vless-cdn/fullchain.pem 与 /etc/ssl/vless-cdn/privkey.pem,属主为 root,私钥权限 0600。
把源站 TCP 443 限制为只接受 CDN 公布的地址段,客户端就无法绕过边缘直连。[8] 保留 SSH 规则,以及仍需访问服务器的证书续期路径。CDN 更新地址段时要重新核对,过期的名单可能让入口在没有提示的情况下失效。
从官方 v26.3.27 发布页下载 Linux 64 位压缩包,查看发布说明和官方提供的校验材料,把可执行文件安装到 /opt/xray-cdn/v26.3.27/xray,属主 root,权限 0755。用 /opt/xray-cdn/v26.3.27/xray uuid 生成 UUID,并为每种传输选一个随机路径段。创建不可登录的系统账号 xray-cdn,把下面内容保存为 /etc/xray-cdn/server.json,权限 0640,属主 root:xray-cdn。[1]
{
"log": {"loglevel": "warning"},
"inbounds": [
{
"tag": "vless-ws",
"listen": "127.0.0.1",
"port": 10001,
"protocol": "vless",
"settings": {"clients": [{"id": "REPLACE_UUID"}], "decryption": "none"},
"streamSettings": {"network": "ws", "wsSettings": {"path": "/ws-REPLACE_SECRET"}}
},
{
"tag": "vless-xhttp",
"listen": "127.0.0.1",
"port": 10002,
"protocol": "vless",
"settings": {"clients": [{"id": "REPLACE_UUID"}], "decryption": "none"},
"streamSettings": {"network": "xhttp", "xhttpSettings": {"path": "/xh-REPLACE_SECRET/", "mode": "packet-up"}}
}
],
"outbounds": [{"tag": "direct", "protocol": "freedom"}]
}
只保留你所选传输对应的那个入站。两个入站都不启用 TLS,因为 TLS 在同一台主机的 Nginx 上终结;这只在两者都监听 127.0.0.1 时才安全。VLESS 的 decryption: none 表示 VLESS 本身不额外加密。用 sudo -u xray-cdn /opt/xray-cdn/v26.3.27/xray run -test -config /etc/xray-cdn/server.json 检查配置,再以 xray-cdn 账号作为 systemd 服务运行。
为 proxy.example.com 添加一个 server 块。除秘密路径外,所有路径都返回 404,扫描源站的人只会看到一个背后什么都没有的普通 HTTPS 站点。
server {
listen 443 ssl;
server_name proxy.example.com;
ssl_certificate /etc/ssl/vless-cdn/fullchain.pem;
ssl_certificate_key /etc/ssl/vless-cdn/privkey.pem;
location = /ws-REPLACE_SECRET {
proxy_pass http://127.0.0.1:10001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 300s;
}
location /xh-REPLACE_SECRET/ {
proxy_pass http://127.0.0.1:10002;
proxy_http_version 1.1;
proxy_buffering off;
proxy_request_buffering off;
proxy_set_header Host $host;
proxy_read_timeout 300s;
}
location / { return 404; }
}
WebSocket 块传递 Upgrade 和 Connection 头,否则逐跳代理会把它们丢掉。[9] XHTTP 块关闭双向缓冲;在 proxy_http_version 1.1 下,Nginx 可以边收边把请求体交给 Xray,而不是先收齐再转发。[10] XHTTP 用前缀匹配,因为每个请求都会在路径后追加自己的后缀。先运行 sudo nginx -t,通过后再重载。
在 Ubuntu 客户端安装同一版本的 Xray,为 WebSocket 路线保存一个私有 client.json(权限 0600):
{
"inbounds": [{"listen": "127.0.0.1", "port": 1083, "protocol": "socks", "settings": {"auth": "noauth", "udp": false}}],
"outbounds": [{
"tag": "cdn-ws",
"protocol": "vless",
"settings": {"vnext": [{"address": "proxy.example.com", "port": 443, "users": [{"id": "REPLACE_UUID", "encryption": "none"}]}]},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {"serverName": "proxy.example.com", "allowInsecure": false},
"wsSettings": {"path": "/ws-REPLACE_SECRET"}
}
}]
}
选择 XHTTP 时,保留同一个出站,只替换传输字段:
"network": "xhttp",
"xhttpSettings": {"path": "/xh-REPLACE_SECRET/", "mode": "packet-up"}
地址和 serverName 都写你的域名,不写源站 IP,这样客户端的 TLS 会话在边缘终结,证书校验保持开启。运行 xray run -test -config ./client.json,然后在前台启动客户端,只让一个测试应用使用 SOCKS5 127.0.0.1:1083。
通过代理打开一个网页,只能说明“某条路径”可用。每次只改一个条件,分别检查每道边界,测试之间恢复可用的配置。
| 检查方法 | 预期现象 | 不符时的处理 |
|---|---|---|
对自己的端点执行 curl --proxy socks5h://127.0.0.1:1083 https://check.example.net/health | 经代理得到预期响应 | 先看 Nginx 和 Xray 日志,再考虑换传输 |
dig +short proxy.example.com | 返回 CDN 边缘地址,而不是 VPS IP | 记录没有走代理;先修 DNS,再信任其它结果 |
在外部主机执行 curl --resolve proxy.example.com:443:ORIGIN_IP https://proxy.example.com/ | 连接超时或被拒绝 | 源站防火墙仍放行非 CDN 来源 |
经边缘请求 https://proxy.example.com/wrong-path | Nginx 返回 404 | location 范围过宽,转发了多余路径 |
| 客户端副本换成另一个有效 UUID | 代理请求失败 | 确认旧客户端进程已停止、UUID 列表正确 |
客户端副本使用边缘证书上没有的 serverName | TLS 校验失败 | 保持 allowInsecure: false,不要靠关闭校验来“修复” |
然后在设置了本地 SOCKS 端口的浏览器中打开 IP 地址检测工具。它应显示 VPS 的出口地址:CDN 只承载入站这一段,Xray 的 freedom 出站从服务器发出。这个结果只覆盖浏览器这一个请求,不代表其它应用的 DNS、IPv6 或 UDP。
如果 WebSocket 请求失败,而同一边缘上的普通 HTTPS 正常,可以用 WebSocket 失败但 HTTPS 正常的排查方法区分 CDN 设置、代理和客户端问题。XHTTP 方面,如果 CDN 会在空闲后切断下行,表现为长请求中途断开;XHTTP 讨论帖指出,Cloudflare 会切断 100 秒没有实际数据的 HTTP 响应。[6]
修改前,私下保存 server.json、Nginx 站点文件、防火墙规则和客户端文件的副本。客户端回退就是恢复之前的配置,并用一次新请求确认。服务器端停用新的 Nginx 站点和 xray-cdn 服务,重载 Nginx,再用 sudo ss -lntp 确认 10001 和 10002 端口已无人监听。
彻底停用时,删除这条代理 DNS 记录或关闭它的 CDN 代理,从剩余配置中删除该 UUID;如果源站证书不再有其它用途,就吊销或删除它。只为 CDN 设的防火墙规则最后再删,先弄清服务器上还有哪些站点依赖 443 端口。升级也按同样方式:准备新的版本目录,对两个文件运行 -test,重做上面的验证表后再切换服务。
packet-up,同一客户端不要两者混用。不会自动更私密。CDN 会终结客户端的 TLS,再自行连接你的源站,因此它能看到承载 VLESS 流量的那段代理 HTTP 流,隐私边界要按这一点来评估。
不建议。Flexible 从边缘到源站不使用 TLS;Full (strict) 会校验源站证书,既保护第二段传输,也能防止有人冒充你的源站接收流量。
可以,像示例那样分别使用独立的秘密路径和独立的 Nginx location 即可。但每个客户端只用一种传输,出现故障时才能判断是哪条路径的问题。
项目指南把 packet-up 列为在 CDN 和反向代理后兼容性最强的模式,它也让源站保持普通 HTTP/1.1,不需要额外的 gRPC 设置。
只有源站防火墙只放行 CDN 地址段时才行。没有这条规则,任何知道 VPS 地址的人都可以直接连接 Nginx,完全绕过边缘节点。
不能。经 CDN 的入口仍可能被限速、过滤,或被 CDN 自身限制,边缘节点重启也会关闭已打开的连接,所以请另外保留一条恢复路径。
按固定周期核对 CDN 公布的地址段,并在收到服务商通知后立即检查。过期的放行名单会悄悄拒绝来自边缘节点的正常回源连接。
免责声明: 本文仅供一般信息参考,不构成法律、技术或其他专业建议。我们不保证内容的准确性、完整性或时效性。
来源:
Sources checked 2026 年 10 月 14 日。
延伸阅读:
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。