很多 VPS 网站接入 Cloudflare 后,只是把 DNS 记录点成橙云代理。这样能隐藏一部分访问路径,但如果源站 IP 已经泄露,攻击者仍然可以绕过 Cloudflare,直接打你的 VPS。
Cloudflare Tunnel 解决的是另一个问题:让源站不再需要开放公网 80/443 端口。VPS 上运行一个 cloudflared 守护进程,它主动向 Cloudflare 建立 outbound-only 加密连接;外部用户访问你的域名时,请求先进 Cloudflare,再通过这条隧道转发到 VPS 本地服务。
这篇文章按 VPS 用户的真实场景讲:什么时候该用 Tunnel,怎么创建隧道,怎么发布一个自托管服务,怎么保护后台,以及常见故障怎么排查。
Cloudflare Tunnel 最适合这些需求:
| 场景 | 是否适合 | 说明 |
|---|---|---|
| 暴露博客、工具站、小型 SaaS | 适合 | 免开放源站 80/443,隐藏源站 IP |
| 暴露 n8n、Gitea、Grafana 管理后台 | 很适合 | 可配合 Cloudflare Access 做登录保护 |
| 家宽/NAT 后面的服务 | 适合 | 不需要公网 IP,也不需要端口转发 |
| 高并发下载站、大文件业务 | 谨慎 | 要考虑 Cloudflare 策略和带宽特征 |
| 邮件服务器、游戏服、任意 TCP 服务 | 不一定 | HTTP 最简单,非 HTTP 要看协议和方案 |
一句话:如果你的服务本质是 HTTP/HTTPS,并且你希望隐藏源站 IP,Tunnel 很值得用。
但它不是银弹。Tunnel 不能替你修复应用漏洞,也不能替代备份、日志和权限控制。它解决的是“入口暴露面”和“源站绕过 Cloudflare”的问题。
传统方式是:
用户 -> Cloudflare -> VPS 公网 IP:443 -> Nginx -> 应用
Tunnel 方式是:
用户 -> Cloudflare Edge -> cloudflared 隧道 -> 127.0.0.1:3000
关键区别是:cloudflared 主动从 VPS 连出去,VPS 防火墙可以关闭 80/443 入站,只保留 SSH 或甚至只走控制台/VPN 管理。
Cloudflare 官方文档也明确说明,Tunnel 使用 outbound-only connection model:cloudflared 从源站主动连接到 Cloudflare 全球网络,流量再通过这条连接双向转发。
这对 VPS 很有价值:
- 源站 IP 不必直接暴露给用户;
- 没有公网 IP 的内网服务也能发布;
- 可以把后台入口挂到 Cloudflare Access 后面;
- 防火墙策略更简单:默认拒绝入站,只允许必要管理端口。
你需要:
- 一个已经接入 Cloudflare 的域名;
- 一台能访问外网的 VPS;
- 一个本地正在运行的服务,例如
127.0.0.1:3000; - Cloudflare Zero Trust 面板访问权限。
先确认本地服务可访问:
curl -I http://127.0.0.1:3000
如果本机都访问不了,先别配置 Tunnel。Tunnel 不是应用修复工具,它只负责转发。
进入 Cloudflare Zero Trust:
Zero Trust -> Networks -> Connectors -> Cloudflare Tunnels -> Create a tunnel
选择 Cloudflared,给隧道起名,比如:
vps-main-tunnel
Cloudflare 会给你一条安装命令。Debian/Ubuntu 上大概是这种形式:
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
sudo cloudflared service install <你的-token>
安装后回到面板,如果 connector 显示 Healthy,说明 VPS 已经和 Cloudflare 建立连接。
在 Tunnel 的 Public Hostname 或 Published applications 里添加:
Subdomain: app
Domain: example.com
Type: HTTP
URL: http://localhost:3000
保存后,访问:
https://app.example.com
如果服务正常,就会通过 Cloudflare Tunnel 打到 VPS 本地的 3000 端口。
这时你的应用可以只监听本地:
HOST=127.0.0.1 PORT=3000 npm start
Nginx 也可以不是公网入口,而只是本机反代层:
server {
listen 127.0.0.1:8080;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
然后 Tunnel 指向:
http://localhost:8080
Dashboard 安装方式通常会自动注册 systemd 服务。检查状态:
systemctl status cloudflared
journalctl -u cloudflared -n 100 --no-pager
常用命令:
systemctl restart cloudflared
systemctl enable cloudflared
如果你以后重装系统,记得重新安装 connector。Tunnel 对象在 Cloudflare 面板里,VPS 上的 cloudflared 只是连接器。
使用 Tunnel 后,公网入站端口可以大幅收紧。
如果你的站点完全通过 Tunnel 发布,可以这样:
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw enable
如果 SSH 也想进一步保护,可以只允许自己的 IP:
ufw allow from 你的固定IP to any port 22 proto tcp
但不要在没准备控制台/VNC/救援模式前乱关 SSH。之前已经有相关自救文章:
Tunnel 的强项不只是隐藏源站,还能和 Cloudflare Access 配合。
比如你有这些后台:
n8n.example.comgitea.example.comgrafana.example.comadmin.example.com
可以在 Zero Trust 里创建 Access Application,要求访问前必须通过:
- 邮箱 OTP;
- Google / GitHub 登录;
- 指定团队邮箱;
- 指定国家/地区或 IP 策略;
- 多因素认证。
这样即使后台应用本身登录页暴露,外面还多了一层 Cloudflare 身份验证。
推荐策略:
| 服务 | Access 建议 |
|---|---|
| 博客前台 | 不需要 Access |
| n8n / Grafana / Gitea 后台 | 强烈建议加 Access |
| Webhook URL | 不要盲目加 Access,可能影响第三方回调 |
| 内部工具 | 只允许指定邮箱或组织账号 |
先看服务:
systemctl status cloudflared
journalctl -u cloudflared -n 100 --no-pager
再确认 VPS 能访问 Cloudflare:
curl -I https://www.cloudflare.com
如果服务器在严格防火墙后面,需要确认 outbound 连接没有被拦。Cloudflare 文档提醒,受限网络里要先做 connectivity pre-check,尤其要确认到 Cloudflare 的连接可达。
常见原因:
- token 复制错;
- systemd 服务没启动;
- VPS 出站被防火墙拦;
- DNS 或系统时间异常;
- cloudflared 版本过旧。
Tunnel 已经 Healthy,但访问域名报错,通常是本地服务地址写错。
在 VPS 上测试:
curl -I http://localhost:3000
curl -I http://127.0.0.1:3000
注意 localhost 可能解析到 IPv6 ::1,而你的应用只监听 IPv4。遇到这种情况,Public Hostname 里可以明确写:
http://127.0.0.1:3000
如果你的应用要求 Host 头,可能还要在 Tunnel 的 origin request 设置里调整 HTTP Host Header。
Tunnel 配好了,不代表源站一定隐藏。你还要确认:
- DNS 里没有灰云 A 记录暴露真实 IP;
- VPS 防火墙没有继续开放 80/443;
- 历史 DNS 记录、证书透明日志、邮件头没有泄露源站;
- 旧的 Nginx 入口没有继续监听公网。
测试源站直连:
curl -I http://你的VPS_IP
curl -kI https://你的VPS_IP
如果还能访问到网站,就说明源站还没真正收口。
| 对比项 | 普通橙云代理 | Cloudflare Tunnel |
|---|---|---|
| 是否需要公网入站 80/443 | 需要 | 不需要 |
| 是否隐藏源站 IP | 部分隐藏 | 更彻底,但仍要清理历史泄露 |
| 是否适合 NAT/家宽 | 不适合 | 适合 |
| 是否支持 Access | 支持 | 支持,体验更完整 |
| 排障复杂度 | 较低 | 略高 |
普通橙云已经能解决很多 CDN/WAF/缓存问题;Tunnel 更适合你想进一步缩小 VPS 暴露面,或者没有公网入站条件的场景。
发布服务前,至少检查:
- 本地服务
curl http://127.0.0.1:端口正常; - Cloudflare Tunnel connector 显示 Healthy;
- Public Hostname 指向正确本地端口;
- UFW 没把 SSH 锁死;
- VPS 公网 80/443 已关闭或不再返回业务页面;
- 后台域名已加 Cloudflare Access;
- Webhook 路径没有被 Access 误拦;
-
journalctl -u cloudflared没有持续错误; - 域名访问、直连 IP、移动网络都测试过。
这些情况要谨慎:
- 你需要完全控制 Nginx TLS 细节和证书链;
- 业务有大量大文件下载或特殊协议;
- 你不想把入口强依赖 Cloudflare;
- 你所在网络对 Cloudflare 出站连接不稳定;
- 你需要非 HTTP 协议但不想引入额外客户端或 Zero Trust 配置。
如果只是普通网站、管理后台、自托管工具、内部面板,Tunnel 的收益通常大于复杂度。
Cloudflare Tunnel 很适合 VPS 用户做三件事:隐藏源站 IP、减少公网入站端口、给后台服务加一层 Zero Trust 访问控制。
它的核心不是“让网站更快”,而是“让源站更少暴露”。如果你已经接入 Cloudflare,又担心源站被直连、后台被扫、家宽/NAT 没法开放端口,那么 Tunnel 是非常值得掌握的一套方案。
真正安全的做法是:Tunnel 发布服务,防火墙关闭不必要入站,后台用 Access 保护,日志持续观察。这样 VPS 才不是孤零零暴露在公网,而是放在 Cloudflare 边缘网络后面受控访问。
