开荒笔记 · Homelab
Cloudflare One · 国内实战

无公网 IP 也能开荒:一台国内 ECS 跑通 Tunnel + Mesh 的完整教程

对内用 WARP Mesh 做管理通道,对外用 Named Tunnel 按域名发布 SSH;QUIC 全挂时强制 http2 + 手动优选 edge,把注册 40 秒压到 6 秒、握手 5 秒压到 1 秒。本文整理自一线换机实录,占位符可直接替换落地。

谢昱成 · Homelab 开荒记录者  ·   ·  阅读约 18 分钟

题图占位:深色底 + 橙青双色光斑,象征美西 lax 与新加坡 sin 双 PoP 接入。正式发布时可替换为真实架构截图。

占位符约定:本文所有 <HOST><SSH_DOMAIN><TUNNEL_ID><TEAM_NAME> 均为占位符,真值只存在本地 ~/.ssh/ 与 Access Dashboard,绝不进 git。

SECTION 00架构:两条路,各管一摊

目标机器是一台国内 ECS(实测 Huawei Cloud EulerOS,无公网 IP 也可)。我们刻意把“管理”与“发布”拆成两条正交通道,避免单点故障互相拖累。

管理: 笔记本/enroll 设备 ──► Mesh 100.96.0.0/12 ──► <HOST> (warp-cli, CloudflareWARP 网卡) 发布: 外网 ──► <SSH_DOMAIN> ──► CF 边缘 ──► tunnel (cloudflared 出站, 无需开端口) └─► Access 策略 (邮箱 Allow / Bypass 仅临时测速) ──► 127.0.0.1:22
Tunnel 是 inbound(发布),不能当梯子;出海靠 warp-cli 这条 daemon。两条线职责切分是全文的前提。
图 1 · 双通道架构:Mesh 管内网管理,Tunnel 管公网按域名发布。

SECTION 01基线:先接受三个现实

国内网到 Cloudflare 边缘有三道“默认 debuff”,越早接受,越少走弯路。实测结论是:打穿就好,别追 QUIC。

7844 挂UDP / QUIC 全挂,强制 http2
~40KB/sGitHub 直下龟速,走官方源
~184mswarp ping,钉到 lax / sin
  1. UDP/QUIC(7844)全挂:cloudflared 必须 --protocol http2,warp 的 MASQUE 也会退化。
  2. GitHub 龟速:别从 GitHub release 下二进制,走 pkg.cloudflare.com 官方源。
  3. 到边缘绕路:实测钉到美西 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
EulerOS 坑:打开 /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 仅临时测速,测完立刻删。
Pin 住 edge 不是玄学,是把 40 秒注册压到 6 秒的唯一实测手段。—— 但 pin 错一个 PoP,4 连接会压成 1 条,HA 直接降级

SECTION 05edge 优选:注册 40s → 6s,握手 5s → 1s

默认选路会被钉到慢 PoP。手动采样 TCP:7844(60 个点,region1/region2 × v4/v6)结论非常清晰:

分组结果延迟
region1 IPv6(...:a0::/9610 个全通约 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:

  1. 建 token:Zero Trust → Access → Service Auth → Create,记下 client_id(形如 <ID>.access)与 client_secretcfast_...,只显示一次)。注意读的是 client_secret、传的是 client_id,不是 UUID。
  2. 先配注册策略,否则 400/403:Devices → Management → Device enrollment permissions → Policies → Action 选 Service Auth → Include 选 Service Token → 挂到 enrollment 规则。这一步只能 dashboard 点,API 无端点(试过 6 个候选全 400/404)。
  3. 写 mdm.xml/var/lib/cloudflare-warp/mdm.xmlchmod 600):
<dict>
  <key>organization</key><string>&lt;TEAM_NAME&gt;</string>
  <key>auth_client_id</key><string>&lt;CLIENT_ID&gt;</string>
  <key>auth_client_secret</key><string>&lt;CLIENT_SECRET&gt;</string>
  <key>auto_connect</key><integer>1</integer>
  <key>onboarding</key><false/>
</dict>
  1. systemctl restart warp-svc,看 service_token_registrationresult=Ok 即成功;400 = 缺策略;403 = token 没进策略(新建 token 要重挂一次)。
  2. warp-cli --accept-tos connectip -4 addr show CloudflareWARP 拿到 100.96.0.x/32 即 Mesh 上线。
别忘了打开 Devices → Management 的对等连接(Mesh)开关,否则设备间不通;token 到期会掉线,建议用长期 token 并到期前换 mdm 重启。warp 出站是单点、Tunnel 才是双副本——别搞反。

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)
    ...

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
收尾卫生:Bypass 策略删、临时 token 全删、access 监听全杀、secret 文件清掉;gate 恢复 302 即干净。
via-tunnel #1: 1.39s b'SSH-2.0-OpenSSH' via-tunnel #2: 1.00s b'SSH-2.0-OpenSSH' via-tunnel #3: 0.99s b'SSH-2.0-OpenSSH' ← 优选后 5–8 倍提升
三次握手全部 1 秒级,banner 一出即判定打通,无需完整登录。
图 2 · 优选后三次握手计时示意:从 5 秒级降至 1 秒级。

SECTION 09出海与地区判定:实测结论

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。本文为整理后的教程排版,命令与结论与原文一致,占位符未替换真值。

谢昱成 · Homelab 开荒记录者

专注国内网络环境下的 Cloudflare One 落地:Tunnel 发布、WARP Mesh 组网与 edge 优选。本文所有敏感值均为占位符,真值只存本地与 Dashboard。欢迎带着你的 PoP 实测数据来对答案。