没有公网 IP,也别急着做端口映射:用 Cloudflare Tunnel 发布家庭服务

0 阅读3分钟

我现在更倾向于把家庭服务器的 Web 服务这样接到公网:

访客
  ↓
Cloudflare 边缘网络
  ↓
Cloudflare Tunnel
  ↓
家里的 cloudflared
  ↓
http://127.0.0.1:3000

核心变化只有一个:不再等待公网主动连接家里的路由器,而是让 cloudflared 从内网主动建立到 Cloudflare 的出站连接。

这对没有公网 IPv4、无法做端口映射,或者不希望直接暴露家庭出口地址的人很实用。但 Tunnel 不是“安装完就自动安全”的魔法。它只解决连接路径,应用自己的认证、授权和漏洞仍然要自己处理。

先分清公开服务和私人访问

公开网站、演示站、Webhook 接口,可以通过 Published application 映射到公开域名。

NAS 管理页、路由器后台、SSH、数据库等内部服务,不应该直接对所有访客开放。至少要叠加 Cloudflare Access 身份认证,或者改用 VPN/组网方案。

如果只是想远程打开自己的内网设备,直接照搬公开网站方案,通常是在解决一个问题的同时制造另一个问题。

开始前先验证本地服务

假设网站运行在本机 3000 端口,先执行:

curl -I http://127.0.0.1:3000

这里必须先返回正常结果。否则,即使 Tunnel 本身在线,Cloudflare 也只会把请求转发到一个无法访问的本地端口。

建议同时确认:

  • 应用到底监听 127.0.0.10.0.0.0 还是容器内部地址;
  • 宿主机和容器之间是否正确映射端口;
  • cloudflared 运行的机器能否访问目标服务;
  • 本机是否已经存在另一套 cloudflared 服务。

创建 Tunnel

在 Cloudflare 控制台进入:

Networking → Tunnels → Create Tunnel

创建一个便于识别的 Tunnel,例如 home-web,然后选择服务器对应的操作系统和架构。后台会给出安装命令,其中包含 Tunnel Token。

Token 不应该出现在截图、Git 仓库、聊天记录或公开日志里。拿到它的人可能运行新的连接器,接入你的 Tunnel。

安装完成后检查服务状态:

systemctl status cloudflared
journalctl -u cloudflared --no-pager -n 100

如果是 Docker 或其他安装方式,则使用对应的容器和进程日志检查。

把域名映射到本地端口

进入刚才创建的 Tunnel:

Routes → Add route → Published application

例如:

Hostname: app.example.com
Service URL: http://127.0.0.1:3000

保存后,请求 https://app.example.com 会经过 Cloudflare,再由 Tunnel 转发到本地 3000 端口。

如果目标服务在局域网另一台机器上,可以填写那台机器的内网地址。前提仍然是 cloudflared 所在主机能够直接访问该地址。

我会额外加的安全门槛

即使不开放路由器端口,应用仍然进入了公网访问路径。至少要做这些事:

  1. 管理界面增加可靠的登录和访问控制;
  2. 不公开数据库、Redis、Docker API 和路由器管理端口;
  3. Token 不进入 Git,并限制服务器配置文件权限;
  4. 更新应用依赖,修复应用本身的漏洞;
  5. 检查上传、注册、密码重置和调试接口;
  6. 保留 Tunnel 与应用日志,设置异常自动重启。

WAF、CDN 和隐藏源站地址都不能代替应用安全。Cloudflare Tunnel 减少的是公网入口和家庭网络配置,不是安全责任。

502 时不要先重装

排查顺序应该从内到外:

  1. curl 本地服务;
  2. 检查应用监听地址和容器端口;
  3. 查看 cloudflared 状态与日志;
  4. 核对 Service URL 的协议、地址和端口;
  5. 最后再看域名、HTTPS 和 Cloudflare 后台状态。

很多 502 并不是 Tunnel 坏了,而是本地应用没有真正运行在你填写的地址上。

官方文档:

对于个人网站、开发预览和轻量公开服务,这套路径比申请公网 IP、配置 DDNS、开放端口更省事。对于私人管理服务,则要在 Tunnel 之上增加身份验证,而不是把它直接暴露出去。