跳到正文
从开放 80/443 到 Cloudflare Tunnel:连接方向改变了什么
从开放 80/443 到 Cloudflare Tunnel:连接方向改变了什么

从开放 80/443 到 Cloudflare Tunnel:连接方向改变了什么

Tunnel 让源站主动连接 Cloudflare,从而关闭公网 Web 入站;它缩小暴露面,却不会替代身份验证、凭据保护、独立管理通道和故障恢复。

速读#

我最初发布 Web 服务的方式很直接:VPS 公网开放 80/443,Nginx 接住请求,再转给应用。Cloudflare 代理能让正常 DNS 解析返回边缘地址,也能提供缓存和 WAF,但如果源站仍接受全网直连,历史 DNS、其他子域或同机服务一旦暴露 IP,访问者仍可能绕过边缘。Cloudflare Tunnel 改变的不是端口数字,而是连接发起方向:cloudflared 主动建立出站通道,公开 Web 服务因此不再需要公网入站端口。

这不等于服务器“没有攻击面”,也不等于应用自动获得认证。公开域名仍然可以被任何人访问,Cloudflare 成为 TLS 与流量路径中的受信第三方,Tunnel 凭据泄露、出站网络中断、账号或边缘故障都会影响服务。我的最终取舍是:公共 Web 走 Tunnel,管理面走独立的 WireGuard、受限 SSH 或云厂商控制台,两条链不要互相成为唯一救援入口。

三种入口模型不是简单的安全等级#

传统直连由访客或反向代理主动连接源站公网端口。它最容易理解,也没有额外 Tunnel 依赖,但必须维护证书、防火墙、DDoS 防护和源站暴露面。端口扫描本身不等于入侵,却会持续验证服务版本、弱口令和错误配置;公开的每个服务都需要独立更新、认证和日志,而不是只靠换一个高端口隐藏。

Cloudflare 普通代理在访客与源站之间增加边缘层。正常用户访问 Cloudflare,边缘再回源到 80/443;源站 IP 不再出现在当前代理 DNS 结果中,但“隐藏”不能当访问控制。一个可行的中间方案是让源站防火墙只接受 Cloudflare 官方 IP 段,并使用 Authenticated Origin Pulls 或等价的源站认证,这样即使 IP 被发现,普通直连也会被拒绝。它仍需要维护入站规则、Cloudflare 地址变化和源站证书,但并非一泄露 IP 就必然失守。

Tunnel 则让源站不再等待公网 Web 入站。cloudflared 从内网向 Cloudflare 建立长连接,边缘把匹配主机名的请求沿既有通道送回本机服务:

浏览器 -> Cloudflare 边缘 -> Tunnel -> cloudflared -> 回环 Nginx/应用

家庭宽带、CGNAT 或没有公网地址的机器也能使用这种模式,因为源站只需要正常出站。frp 等自建反向隧道采用相似的连接方向,只是公开入口落在自己维护的中转机上;选择哪一种,本质上是在自建运维、供应商依赖、协议能力和信任边界之间取舍。

入口方式公网 Web 入站入口由谁维护主要代价
源站直连源站开放自己暴露面、证书、DDoS 与防火墙全部自理
Cloudflare 代理 + 源站限流/认证源站只允许边缘Cloudflare + 自己仍维护入站 allowlist 与源站 TLS
自建 frp/反代中转中转机开放,源站出站自己多一台公网入口和完整运维责任
Cloudflare Tunnel源站无需公网 Web 入站Cloudflare供应商、账号、出站链路和支持协议的依赖

Tunnel 改变了什么,又没有改变什么#

它最直接地减少了源站监听面。当前站点的 Nginx 只监听 127.0.0.1:80,Cloudflare 请求通过 Tunnel 到达本机,公网扫描源站 IP 也无法直接连接这个 Web 端口。这样比“端口开放但希望 IP 不被发现”更容易验证,因为监听地址本身已经收紧。

但 Tunnel 不负责判断谁是管理员。公开文章可以直接访问,/admin 仍要交给 Cloudflare Access 和应用自身 OAuth,webhook 仍要验证 GitHub HMAC 签名。Tunnel 只回答“这条请求怎样到达服务”,不回答“请求者是否有权执行操作”。如果同一 Tunnel 还配置了备用主机名,也要确保它们没有绕过主域名上的 Access 规则。

它也没有让源站 IP 必然保密。同一台服务器若仍公开 WireGuard、SSH、邮件或其他 DNS 记录,外部仍可能知道地址;区别是 Web 服务不再接受这个地址上的直接入站。若隐藏源站本身是关键目标,公共 Web 源站与公网 VPN/邮件入口应考虑分离,不能让另一个同机服务把地址重新暴露后又依赖“没人知道 IP”。

隐私边界同样要说清。访客 HTTPS 通常在 Cloudflare 边缘终止,Cloudflare 可以执行 WAF、缓存和路由,也处在能够处理明文应用数据的位置;边缘到 cloudflared 的通道再被保护。对公开博客,这个交换通常可以接受;对不能交给第三方处理的敏感业务,应评估端到端加密、数据类型和其他入口方案,而不是因为名字里有 Tunnel 就默认隐私更强。

编排层怎样真正做到不发布端口#

如果 cloudflared 与应用都在 Compose 中,可以把它们放进一个专用网络,让 Tunnel 通过服务名访问应用。应用不配置 ports,宿主机就不会因为 Compose 映射出新的公网监听;expose 可以记录容器使用的端口,但它不是防火墙,同一网络中的其他容器即使没有 expose 也可能直接访问服务。真正的边界来自不发布宿主机端口、控制容器加入哪些网络,以及应用自身仍有认证。

部署后不能只看 Zero Trust 控制台显示 Healthy,要在主机与外部分别验证:

Terminal window
sudo ss -lntup
docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ufw status numbered
curl -I -H 'Host: s1oopx.bond' http://127.0.0.1/

前三项确认真实监听、容器发布端口和防火墙,最后一项确认本机 Nginx 在不经过 Cloudflare 时能够按主机名提供内容。还应从另一台外部主机测试源站 IP 的 80/443 确实不可达;只在服务器本机成功访问,不能证明公网边界正确。

Tunnel Token 是运行凭据,不是普通配置#

Token 或命名 Tunnel 凭据允许连接器加入既有隧道,泄露后应按密钥处理:立即轮换或删除旧凭据,并检查账号与 Tunnel 活动。把值放进 .env 并加入 .gitignore 只能避免一次常见误提交,不能防止文件权限过宽、备份外泄、shell 历史、进程参数、docker inspect 或日志把它带出去。

小规模部署至少应把凭据放在仓库外、限制为运行用户可读,例如权限为 0600 的环境文件或受控的 systemd/容器秘密注入,并确保日志不打印完整命令与环境。Git 历史也要检查:一个值曾经提交过,再从最新版本删除并不等于它没有泄露。凭据轮换步骤应提前记录,因为隧道故障时临时搜索控制台往往最容易误操作。

反向代理后的 HTTPS 语义要逐跳传递#

WordPress 阶段我遇到过重定向循环:访客在 Cloudflare 侧使用 HTTPS,Tunnel 到 Nginx、Nginx 到 WordPress 却可能是 HTTP,应用只看到内层协议后不断要求跳转。这个问题不能简化成“补一行 X-Forwarded-Proto $scheme”,因为 Nginx 自己收到的 $scheme 在回环 HTTP 链路里可能正是 http,反而会覆盖 Cloudflare 已经提供的外层语义。

正确做法是先确定哪一跳可信,由入口代理清理客户端伪造的转发头,再把真实访客协议传给应用;如果某个 Nginx listener 只可能由 HTTPS 的 Tunnel 主机名到达,也可以在受控边界内明确设置相应值。WordPress 还需要在受信代理场景中将该值映射为自身的 HTTPS 状态。历史上使用过的处理类似下面这样,但它成立的前提是 Header 只能由受信代理写入:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}

当前 Astro 静态站不再依赖 WordPress 判断协议,但 OAuth、重定向和生成绝对 URL 的服务仍然需要同样的边界意识:转发头是代理之间的契约,不是任意客户端都能声明的事实。

可用性与救援路径要单独设计#

Tunnel 增加了 cloudflared、Cloudflare 账号、边缘服务和出站网络这些依赖。连接器退出后可以由 systemd 拉起,但主机断网、账号配置错误或供应商故障不会因为 Restart=always 自动消失。至少要从外部监控公开 /healthz,让“进程活着但隧道不可用”也能被发现;更高可用需求可以在不同故障域运行多个 connector,但同一台主机上的两个进程不能解决主机故障。

管理入口不能只依赖故障中的 Tunnel。当前更稳的选择是 WireGuard 私网或严格受限的 SSH,再保留云厂商串口/控制台作为最后救援;如果仍公开 SSH,应禁用密码与 root 直登、使用密钥和必要的来源限制。修改 SSH 端口只能减少日志噪声,不是主要安全措施。

我从 Tunnel 学到的核心仍然成立:公网可达不一定要求源站接受公网入站,改变连接方向可以直接删掉一类暴露面。但真正可靠的方案还要同时回答谁能访问、凭据怎样保护、第三方能看到什么、隧道断了怎样发现,以及我从哪条独立通道进去修。少开端口是结果,边界可验证才是目的。

版权许可

CC BY-NC-SA 4.0 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

相关文章

s1oopX

登录 s1oopX