速读#
这篇讲的不是 Tunnel 配置步骤,而是“公网可达”从入站开门转成主动出站后的认知变化。DNS 代理只是藏 IP,端口还在;Tunnel 改的是连接发起方向。读这篇要顺手记住:token 是密钥,WordPress 反代要处理 HTTPS 协议头。
入站思维:开一道缝就多一份攻击面#
最早「让外面访问到服务」只有一个动作:在防火墙开端口放行。公网 IP + ufw allow 80,443 + Nginx,这就叫上线了。
能用,但是入站思维:外面来敲门,我把门开一道缝。隐含代价当时没察觉——开了多少缝,就暴露多少攻击面。fail2ban 日志里每天几百条扫描,本质就是缝在招事。
DNS 代理只是藏,门缝还在#
Cloudflare DNS 接管:NS 改过去,A 记录橙云开启,外面 ping 到的是 CF IP,不是真实 IP。顺手 CDN、SSL、基础 WAF,扫描日志肉眼清净了。
但这只是藏。回源时 CF 仍要从公网打你的 80/443——IP 藏了,端口还在。IP 一旦泄露(邮件头、历史 DNS),照样被打。
当时未解决的问题:能不能连这道缝都不开?
Tunnel:根本不要入站#
我以为「更安全」等于「更严的入站规则」。Tunnel 给的答案是:根本不要入站。
cloudflared 在机器上主动向 Cloudflare 建出站连接,访客请求沿隧道进来。服务器可以对公网零入站端口,服务仍用 HTTPS 域名访问。
可达拆成两层:
- 谁发起连接(入站 / 出站)
- 真实入口暴露在哪
Tunnel 把发起方向改成出站,真实入口归零。家宽、NAT、没有公网 IP 的机器,在出站模型下也能挂服务——出站本来就不依赖公网入站能力。
四种方案对照#
| 方案 | 发起方向 | 真实 IP | 我为何没长期停在这 |
|---|---|---|---|
| 端口转发 / 直挂 | 入站 | 暴露 | 攻击面摊开 |
| frp 等自建中转 | 源站出站连中转,公网入站落在中转机 | 源站可藏,中转暴露 | 暴露面只是挪到了中转机,还多一台要守 |
| CF DNS 代理 | 入站(回源) | 藏了但端口在 | IP 一泄露就破功 |
| CF Tunnel | 出站 | 全程可不暴露 | 真正零入站 |
frp 那行值得多看一眼:它其实已经把源站翻成出站了,思路和 Tunnel 同源。差别在承接入站的那台中转机归谁守——自建中转,暴露面和运维负担都是自己的;Tunnel 等于把这台「中转机」外包给了 Cloudflare 的边缘网络。
选 Tunnel 不是因为它完美:流量经 CF 中转,多一层依赖,出站断了服务就断。在「几台机器、要省心、要少暴露」这个场景下,这个取舍我认。
出站想通后:部署按面拆#
不再把部署看成一串配置步骤,而按系统生命周期分成一个个独立的面:
| 面 | 我现在怎么做 | 状态 |
|---|---|---|
| 可达 | Tunnel 出站,零入站 | 在用 |
| 守护 | systemd 崩溃自拉 | 在用;更底层 watchdog 评估中 |
| 防护 | ufw 只放 SSH + fail2ban | 在用 |
| 可观测 | 哪吒 + 告警 | 在用 |
| 配置密钥 | Tunnel token 进 .env + gitignore | 在用 |
每面独立问「缺了会怎样」。例如守护:systemd 能拉「进程崩了」,拉不起「更彻底的挂」——watchdog 是那一层,没上就照实写评估中。
三个和 Tunnel 强相关的点#
1. token 是密钥,不是配置
能让隧道连上 CF,等于一把钥匙。差点写进 compose.yml,后来进 .env 并 gitignore。和 SSH 私钥同待遇。
2. cloudflared 与 app 同 Compose 网络
用服务名 app:8080 直连,不必走宿主机端口。app 用 expose 而不是 ports——只在 Docker 内网开,不绑宿主机。零暴露落到编排层的动作。
3. WordPress + 反代 / 隧道:HTTPS 死循环几乎必踩 外层 HTTPS、内部 HTTP,WP 会无限重定向。让它信任转发协议头:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on';}和 Nginx 反代漏传 X-Forwarded-Proto 是同一类「内外协议不一致」问题:外层终止了 HTTPS,内层应用只看见 HTTP,就会执着地往 HTTPS 跳,形成死循环。
如果重新来一次#
- 可达面一开始就选 Tunnel,不必先入站再迁移
- SSH 不进 Tunnel——Web 与管理通道分开,隧道自己出故障时,还得有一条不依赖它的路进去修;SSH 靠密钥 + 改端口 + fail2ban 自守
- 守护面更早分层想:「进程崩」和「更彻底的挂」是两级
工具会换,分面的习惯不换。从入站开门,到出站不打门——改变的不是某个配置,是「可达还可以这样理解」。
