本文最后更新于 2026 年 4 月 22 日
本文以 Debian 13 为例,介绍如何搭建 sing-box 的 VLESS + HTTPUpgrade 服务端,通过 Cloudflare Tunnel 隐藏源站 IP,使用 Caddy 建立伪装站,并在客户端启用 ECH 加密 SNI。本文同样完全适用于 Ubuntu 24.04 及以上系统。
本方案有以下特点:
- VPS 不开放任何公网入站端口(防火墙仅允许 SSH 和出站),真实 IP 完全不出现在 DNS 记录、证书或任何公开信息中
- 无需申请 TLS 证书(外层 TLS 由 Cloudflare 边缘节点处理,VPS 内部全程明文 HTTP 回环通信)
- 浏览器直接访问域名显示真实的伪装网站,代理路径隐藏在特定 URI 下
- 客户端启用 ECH 后,中间人仅能看到
cloudflare-ech.com的外层 SNI,无法得知实际访问的域名
注:请先参照 Debian & Ubuntu 服务器的初始化配置 一文对服务器进行各种必要的配置。本文以 sammy 用户为例,并默认已按初始化配置文章对服务器进行了配置。
背景与原理
整体架构
1 | 客户端 sing-box (VLESS + HTTPUpgrade) |
关于 TLS-in-TLS
本方案中,用户访问 HTTPS 网站时产生的内层 TLS 流量被封装在 Cloudflare 的外层 TLS 连接中,TLS-in-TLS 特征不可避免。sing-box 的 multiplex.padding 可在多路复用层添加随机填充以缓解长度特征,但无法完全消除。需要消除 TLS-in-TLS 的场景应选择 AnyTLS + REALITY 或者 VLESS + Vision + REALITY(两者都是直连方案,无法过 CDN)。
本方案不适用的场景
- VPS 无法出站连接 Cloudflare 的场景(极少数网络环境)
- 需要完全消除 TLS-in-TLS 特征的场景
- 追求极致低延迟的场景(CF Tunnel 多一跳,延迟略高于直连)
准备工作
所需资源
- 一台 VPS(任何地区均可,NAT VPS 也可以,只要能出站连接 Cloudflare)
- 一个域名(已托管到 Cloudflare,免费域名即可)
- 一套静态网页内容(推荐,作为伪装站)
下文假设域名为 example.com,代理用子域名 cdn.example.com
安装所需基本工具
1 | sudo apt update && sudo apt install curl vim wget ca-certificates unzip -y |
Cloudflare Tunnel 配置
VPS 安装并配置 cloudflared
1 | sudo mkdir -p --mode=0755 /usr/share/keyrings |
创建 Tunnel
- 登录 dash.cloudflare.com
- 左侧菜单选择 Zero Trust
- 左侧菜单 Networks → Connectors
- 点击 Create a tunnel,选择 Cloudflared
- Tunnel 名称随意填写,点击 Save tunnel
- 下一步会显示安装命令,复制此命令,在 VPS 上执行。
运行复制的命令注册并启动服务:
1 | sudo cloudflared service install eyJhIjoiYWJjZGVmMTIzNDU2Nzg5... |
确认运行状态:
1 | sudo systemctl status cloudflared |
并可在 Cloudflare 网页控制台看到 Connector 已经建立连接,然后点击 Next。
配置 Public Hostname
在页面如此配置:
| 字段 | 值 |
|---|---|
| Subdomain | cdn |
| Domain | example.com |
| Path | (留空) |
| Type | HTTP |
| URL | localhost:8080 |
然后点击 Complete Setup 保存后,Cloudflare 会自动在 DNS 中创建 CNAME 记录 cdn.example.com → <tunnel-id>.cfargotunnel.com。
SSL/TLS 设置
进入 Cloudflare 域名 Dashboard → SSL/TLS:
- Overview → 加密模式设为 Full (strict)(Tunnel 模式下 CF 不经过传统 HTTPS 回源,此设置不影响 Tunnel 通信,选择最严格的模式即可)
- Edge Certificates → Minimum TLS Version:TLS 1.3
- Edge Certificates → TLS 1.3:On
确认 ECH 状态
进入 SSL/TLS → Edge Certificates,找到 Encrypted ClientHello (ECH)。Free 计划域名默认已启用。其他计划确认状态为 Enabled 即可。ECH 的密钥管理与 ECHConfig 发布由 Cloudflare 自动完成,服务端无需任何操作。
VPS 部署
安装 Caddy
1 | sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl |
安装 sing-box
sing-box 官方提供了 APT 仓库,推荐优先使用此方式,便于后续升级。
1 | sudo mkdir -p /etc/apt/keyrings && |
验证版本:
1 | sing-box version |
生成 UUID
1 | sing-box generate uuid |
记录输出的 UUID,服务端与客户端均需使用。
伪装站建设
伪装站的质量直接影响方案的隐蔽性。推荐使用 Hugo 或 Hexo 生成的个人技术博客、摄影作品集、小工具站等。避免使用空白页、默认欢迎页或任何敏感内容。
快速准备一个最简伪装页(注意替换 sammy 为实际用户名)::
1 | sudo mkdir -p /var/www/disguise |
创建 /var/www/disguise/index.html,内容为任意看起来合理的静态网页。如有 Hugo 等静态站生成器,将生成的 public/ 目录内容放入 /var/www/disguise/ 中。
服务端配置文件
生成隐藏路径
1 | openssl rand -hex 16 |
输出示例:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6。将其作为代理路径使用,使用时前面注意加斜杠。
Caddy 配置
编辑 /etc/caddy/Caddyfile,注意替换其中的随机隐藏路径:
1 | sudo vim /etc/caddy/Caddyfile |
1 | { |
auto_https off:TLS 由 Cloudflare 处理,Caddy 不需要管理证书。@proxy matcher 同时检查路径与 Connection: Upgrade 头,浏览器直接访问该路径(没有 Upgrade 头)会落入 file_server 返回伪装页面。
验证并重启:
1 | sudo mkdir -p /var/log/caddy && sudo chown -R caddy:caddy /var/log/caddy |
sing-box 配置
编辑 /etc/sing-box/config.json,注意替换 你生成的 UUID 和路径:
1 | sudo vim /etc/sing-box/config.json |
1 | { |
关键字段说明:
inbounds[].listen:127.0.0.1,仅接收 Caddy 反代过来的请求,不监听公网。
inbounds[].transport.type:httpupgrade,sing-box 推荐的 CDN 传输方式。注意此处不配置 flow 字段——Vision 流控要求底层裸 TCP,与任何 transport 不兼容。
inbounds[].transport.path:必须与 Caddy 配置中的路径完全一致。
验证并启动:
1 | sudo sing-box check -c /etc/sing-box/config.json |
验证服务端
服务状态检查
1 | sudo systemctl status cloudflared # active (running) |
浏览器访问检查
- 访问
https://cdn.example.com→ 应显示伪装网站 - 访问
https://cdn.example.com/任意路径→ 应显示伪装网站 - 访问
https://cdn.example.com/之前生成的随机隐藏路径→ 应显示伪装网站(浏览器不发送 Upgrade 头,Caddy 不会转发到 sing-box)
三项均符合预期,说明伪装站与路径隐蔽性到位。
确认 ECH 可用
在本地终端(非 VPS)执行:
1 | dig cdn.example.com HTTPS @1.1.1.1 |
返回结果中包含 ech=... 字段,说明 Cloudflare 已发布 ECHConfig,客户端可以使用 ECH。
客户端配置文件
以下为客户端示例配置,注意替换 你生成的 UUID 和路径:
1 | { |
客户端关键字段说明
outbounds[].tls.alpn:固定为 ["http/1.1"]。HTTPUpgrade 基于 HTTP/1.1 的 Upgrade 机制,不能使用 h2。
outbounds[].tls.utls:启用 uTLS 伪造 ClientHello 指纹。推荐 chrome,与大多数实际浏览器流量分布一致。
outbounds[].tls.ech:启用 Encrypted ClientHello。sing-box 会自动通过 DNS HTTPS RR 记录获取 ECHConfig。启用后,中间人看到的外层 SNI 为 cloudflare-ech.com,真实的 cdn.example.com 被加密保护。要求客户端的 DNS 服务器支持 HTTPS RR 查询(Cloudflare 1.1.1.1、Google 8.8.8.8 等均支持)。
outbounds[].transport.type:httpupgrade,与服务端一致。
outbounds[].multiplex:启用多路复用。protocol 使用 sing-box 默认的 h2mux(基于 HTTP/2 帧格式,性能与流控最优)。padding: true 在多路复用层添加随机填充,缓解 TLS-in-TLS 的长度特征。
使用优选 Cloudflare IP
如果域名直连 cdn.example.com 延迟较高,可添加多个使用优选 IP 的出站节点。方法是复制 cf-main 的配置,将 server 字段替换为优选 IP(使用 CloudflareSpeedTest 在本地测试获取),保持 tls.server_name 和 transport.host 不变:
1 | { |
将新节点的 tag 加入 urltest 和 selector 的 outbounds 数组即可。
隐蔽性评估
开启 ECH 后,检测者视角:
| 检测维度 | 看到的内容 |
|---|---|
| 连接目标 IP | Cloudflare 的 Anycast IP |
| 外层 SNI | cloudflare-ech.com(所有启用 ECH 的 CF 站点共用) |
| 真实域名 | 加密,不可见 |
| 证书 | Cloudflare 签发的 cloudflare-ech.com 证书 |
| VPS 真实 IP | 不可见(Tunnel 内部通信) |
| 浏览器探测域名 | 正常伪装网站 |
| 路径扫描 | 所有路径均返回伪装页面 |
残留风险:TLS-in-TLS 特征(被 multiplex.padding 缓解但未消除)、流量行为特征(持续连接时长、请求频率模式)。
维护与长期可用性
更新组件
1 | sudo apt update && sudo apt upgrade cloudflared sing-box caddy -y |
定期轮换
建议每 3-6 个月轮换 UUID 与路径:
1 | sing-box generate uuid |
同时更新服务端(sing-box + Caddy)与客户端配置。
常见排查
- 浏览器访问域名显示 Cloudflare 错误页(1033 等):Tunnel 未连接,检查
systemctl status cloudflared - 浏览器显示 502:Caddy 未运行或端口配置错误
- 客户端连接超时:确认 UUID、路径与服务端完全一致;确认
tls.server_name与transport.host都填写了正确的域名 - ECH 未生效(抓包仍看到明文 SNI):确认客户端 DNS 能查到 HTTPS RR 记录(
dig cdn.example.com HTTPS @1.1.1.1),确认返回中包含ech=...字段
References
sing-box - HTTPUpgrade Transport