无公网 IP 也能开荒:一台国内 ECS 跑通 Tunnel + Mesh 的完整教程
对内用 WARP Mesh 做管理通道,对外用 Named Tunnel 按域名发布 SSH;QUIC 全挂时强制 http2 + 手动优选 edge,把注册 40 秒压到 6 秒、握手 5 秒压到 1 秒。本文整理自一线换机实录,占位符可直接替换落地。
管理走 Mesh,发布走 Tunnel:
一条出站连接,打穿无公网 IP 的 ECS
100.96.0.0/12 mesh · ssh://localhost:22 · protocol: http2
题图占位:深色底 + 橙青双色光斑,象征美西 lax 与新加坡 sin 双 PoP 接入。正式发布时可替换为真实架构截图。
<HOST>、<SSH_DOMAIN>、<TUNNEL_ID>、<TEAM_NAME> 均为占位符,真值只存在本地 ~/.ssh/ 与 Access Dashboard,绝不进 git。SECTION 00架构:两条路,各管一摊
目标机器是一台国内 ECS(实测 Huawei Cloud EulerOS,无公网 IP 也可)。我们刻意把“管理”与“发布”拆成两条正交通道,避免单点故障互相拖累。
- 配额先行:tunnel 1000 条 / 每 tunnel 25 副本 / 每副本 4 连接;Access 应用 500 个、service token 50 个。
- 费用:Zero Trust 免费 50 用户,超出约 $7 / 人 / 月;Tunnel 本身不限流量、不按 GB 计费。
SECTION 01基线:先接受三个现实
国内网到 Cloudflare 边缘有三道“默认 debuff”,越早接受,越少走弯路。实测结论是:打穿就好,别追 QUIC。
- UDP/QUIC(7844)全挂:
cloudflared必须--protocol http2,warp 的 MASQUE 也会退化。 - GitHub 龟速:别从 GitHub release 下二进制,走
pkg.cloudflare.com官方源。 - 到边缘绕路:实测钉到美西 lax / 新加坡 sin,SSH 握手秒级,做好心理预期。
SECTION 02装 cloudflared:走官方源,不走 GitHub
EulerOS 上最大的坑不是软件本身,而是 yum repo 里 $releasever 会展开成 2.0 导致 404。硬改 baseurl 是唯一稳妥解。
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg
sudo curl -fsSL https://pkg.cloudflare.com/cloudflared.repo -o /etc/yum.repos.d/cloudflared.repo
sudo dnf install -y cloudflared
# 验证
cloudflared --version
/etc/yum.repos.d/cloudflared.repo,把 baseurl 中的变量段替换为 rpm/9(实测 2026.9.1 有效),再安装。SECTION 03装 warp-cli:同一个 404 坑,别踩两遍
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ <DIST> main" | sudo tee /etc/apt/sources.list.d/cloudflare-warp.list
# EulerOS / rpm 系同理配 repo,同样硬改大版本号
sudo dnf install -y cloudflare-warp
实测版本 2026.7.1377.0。装完先别急着 registration new——headless 注册有严格顺序,见第 6 节。
SECTION 04Named Tunnel:用 credentials-file,别手拼 token
cloudflared tunnel login # 或 dashboard 建 tunnel
cloudflared tunnel create <TUNNEL_NAME> # 得到 <TUNNEL_ID>
/root/.cloudflared/config.yml
tunnel: <TUNNEL_ID>
credentials-file: /root/.cloudflared/<TUNNEL_ID>.json
protocol: http2 # QUIC 挂了只能 http2
edge: # 第 5 节优选结果;IPv6 方括号必须加引号
- "[<EDGE_V6_A>]"
- "[<EDGE_V6_B>]"
- <EDGE_V4_A>
- <EDGE_V4_B>
ingress:
- hostname: <SSH_DOMAIN>
service: ssh://localhost:22
- service: http_status:404
血泪教训:别手拼--token(base64 拼错即报 token 无效)。credentials-file + config 是最稳的组合;DNS 侧<SSH_DOMAIN>CNAME 到<TUNNEL_ID>.cfargotunnel.com并打开 proxied。
pkill -f "cloudflared tunnel" 会连带匹配 SSH 的 ProxyCommand,把自己的会话一起杀掉。请用 pkill -x cloudflared 或精确 pid。Access 侧建一条 Self-hosted(domain=<SSH_DOMAIN>,type 选 ssh),策略先加自己邮箱 Allow;Bypass 仅临时测速,测完立刻删。SECTION 05edge 优选:注册 40s → 6s,握手 5s → 1s
默认选路会被钉到慢 PoP。手动采样 TCP:7844(60 个点,region1/region2 × v4/v6)结论非常清晰:
| 分组 | 结果 | 延迟 |
|---|---|---|
region1 IPv6(...:a0::/96) | 10 个全通 | 约 194ms |
| region2 IPv6 | 全挂 | — |
| 随机 v4 | 零星能通 | 560ms+ |
edge:
- "[2606:4700:a0::8]"
- "[2606:4700:a0::6]"
- 198.41.200.193
- 198.41.200.233
示例为公开 anycast IP,可照抄再按自己环境重测。效果:注册 40s → 6s;SSH 首次握手 5.4/8.4/5.6s → 1.39/1.00/0.99s,提升 5–8 倍。代价:pin 住的 IP 若同属一个 anycast PoP,边缘报 already connected,4 连接压成 1 条——解法是跨 PoP 混 pin(实测 lax08 + sin22),见第 7 节。
SECTION 06warp-cli headless 注册:service token 全流程
浏览器直接点 https://<TEAM_NAME>.cloudflareaccess.com/warp 裸链接没用(无会话,报 Enrollment request invalid),且成功页 token 几分钟过期、多次 registration new 会互顶。正确姿势是 service token:
- 建 token:Zero Trust → Access → Service Auth → Create,记下
client_id(形如<ID>.access)与client_secret(cfast_...,只显示一次)。注意读的是client_secret、传的是client_id,不是 UUID。 - 先配注册策略,否则 400/403:Devices → Management → Device enrollment permissions → Policies → Action 选 Service Auth → Include 选 Service Token → 挂到 enrollment 规则。这一步只能 dashboard 点,API 无端点(试过 6 个候选全 400/404)。
- 写 mdm.xml(
/var/lib/cloudflare-warp/mdm.xml,chmod 600):
<dict>
<key>organization</key><string><TEAM_NAME></string>
<key>auth_client_id</key><string><CLIENT_ID></string>
<key>auth_client_secret</key><string><CLIENT_SECRET></string>
<key>auto_connect</key><integer>1</integer>
<key>onboarding</key><false/>
</dict>
systemctl restart warp-svc,看service_token_registration:result=Ok即成功;400= 缺策略;403= token 没进策略(新建 token 要重挂一次)。warp-cli --accept-tos connect,ip -4 addr show CloudflareWARP拿到100.96.0.x/32即 Mesh 上线。
SECTION 07单机 HA:双 PoP + 双副本 + 自愈
官方上限同 tunnel 25 副本、每副本 4 连接。单机做到顶的配方:edge 混 pin region1-v6 + region2-v4(实测 lax08 + sin22),同一 tunnel 起两个进程各 4 连接,再用 systemd 或 compose 自愈。
services:
tunnel-a:
image: cloudflare/cloudflared:<VERSION>
network_mode: host
restart: always
volumes:
- ./a.yml:/etc/cloudflared/config.yml:ro
- ./<TUNNEL_ID>.json:/etc/cloudflared/<TUNNEL_ID>.json:ro
command: tunnel --config /etc/cloudflared/config.yml run
tunnel-b: # 同上,config 指向 ./b.yml(不同 edge 子集,凑双 PoP)
...
kill -9杀进程:systemd/docker 24 秒内拉起重注册,另一副本零报错零掉线。docker kill不算 crash,不会自愈——测自愈要杀容器内进程,别杀容器。- 迁 docker 后旧 systemd 单元记得
stop + disable,别双跑。
SECTION 08测速:SSH 握手计时 + 用完即删的卫生
Access 邮箱策略会拦 cloudflared access 客户端(要浏览器登录),service token 喂 access 客户端边缘也不认(302,原因悬置)。务实做法:临时 Bypass → 测 → 删。
# 本机起 access 客户端
cloudflared access tcp --hostname <SSH_DOMAIN> --url 127.0.0.1:9211 &
# 三次握手计时(banner 出来即通)
for i in 1 2 3; do python3 -c "import socket,time; s=socket.create_connection(('127.0.0.1',9211),timeout=60); t=time.time(); b=s.recv(30); print(f'via-tunnel #{i}: {time.time()-t:.2f}s {b[:15]!r}'); s.close()"; done
gate 恢复 302 即干净。SECTION 09出海与地区判定:实测结论
- warp 开:Google 302 / FB 200 / YT 200,全通;warp 关:全挂——能上全靠这条 daemon。
- 60 秒 ping:warp 下均值 184ms、3.3% 丢包;直连 0 丢包。短稳、长待 soak。
/cdn-cgi/trace的loc=CN是入口机房标记,不可直配,只能换出口;muse-spark-1.3类出口实测 403 RegionError——仍算 CN。- 看视频:25MB 文件 2.6MB/s(约 20Mbps),1080p 够、4K 悬。http2-only 下大流量仍走 HTTP/2 stream,TCP-over-TCP 在丢包链路上抖。
SECTION 10退场:Tailscale(可选)
Mesh 通之后,本机 tailnet 基本是摆设(daemon 活着但连不上 coordination server,peer 全超时),可删:
systemctl stop tailscaled; systemctl disable tailscaled
rm -f /usr/local/bin/tailscale /usr/local/bin/tailscaled /etc/systemd/system/tailscaled.service
rm -rf /run/tailscale /var/lib/tailscale
systemctl daemon-reload
logout 连不上 coordination 会失败,后台 Machines 里那条 100.64.0.1 去 admin console 手删。
SECTION 11一句话选型
Mesh 管内(约 184ms,可用)+ Tunnel 优选后管外(握手约 1s)——这套在 QUIC 全挂的网下是可用状态;生产 hardening(长期 token、跨机 replica、监控、soak)另起一轮。
原文出处:agent-lessons / cloudflare-one-cn-homelab.md。本文为整理后的教程排版,命令与结论与原文一致,占位符未替换真值。