通过 Cloudflare Tunnel 暴露 Homelab

发布: (2025年12月31日 GMT+8 06:42)
7 min read
原文: Dev.to

Source: Dev.to

我热爱自托管。我在自己的服务器上运行博客、仪表盘以及各种随机实验。我不喜欢的则是端口转发、运营商的 NAT、动态 IP,以及把路由器暴露给整个互联网。

幸好,Cloudflare 提供了一个名为 Cloudflare Tunnel 的解决方案。它让我能够在不在路由器上打开任何入站端口的情况下公开暴露服务。本文介绍了我在生产环境中实际使用它的方式。

“传统”自托管的问题

flowchart LR
    Internet --> Router
    Router --> Server

这意味着:

  • 在路由器上打开端口
  • 信任防火墙配置
  • 希望 IP 不会变化
  • 成为软性 DDoS 目标

对于家庭实验室或个人服务器来说,这是一场灾难的配方,也不是可扩展的解决方案。

Cloudflare 隧道方案

使用 Cloudflare Tunnel 时,方向会改变。不是互联网进入我的网络,而是 我的服务器主动发起连接

flowchart LR
    User --> Cloudflare
    Cloudflare --> Tunnel
    Tunnel --> Server

现在我的服务器仅向 Cloudflare 发起出站连接,Cloudflare 作为公共边缘位于前端。这更加安全:没有开放端口,也不需要公共 IP,从而消除了整类风险。

实际在我的服务器上运行的是什么?

在我的服务器上,我运行一个名为 cloudflared 的小守护进程。

flowchart TB
    cloudflared --> CloudflareEdge
    CloudflareEdge --> LocalService1
    CloudflareEdge --> LocalService2

cloudflared 然后:

  • 打开到 Cloudflare 的加密隧道
  • 使用我的账户凭证进行身份验证
  • 在内部将流量路由到 localhost

因此,我的应用程序从不直接接触公共互联网。

安装 cloudflared

在 Linux 上,安装 cloudflared 大约需要一分钟:

curl -fsSL https://pkg.cloudflare.com/install.sh | sudo bash
sudo apt install cloudflared

快速检查:

cloudflared --version

注意: 通常最好从官方网站下载二进制文件并手动安装;这样可以自行控制更新。

对我的服务器进行身份验证

要对服务器进行身份验证,请运行:

cloudflared tunnel login

浏览器窗口会打开,提示您登录 Cloudflare 账户、选择域名并批准连接。凭证会本地存储在 ~/.cloudflared/cert.pem 中,以供后续隧道使用。

创建隧道

创建隧道的命令:

cloudflared tunnel create 

Cloudflare 会返回隧道的 UUID 和一个用于下载配置文件的 URL。将该文件保存为 ~/.cloudflared/.json。此文件是服务器的身份标识。

我的隧道配置(示例)

配置文件的简化版本:

tunnel: 
credentials-file: ~/.cloudflared/.json

ingress:
  - hostname: blog.example.com
    service: http://localhost:8080
  - hostname: dashboard.example.com
    service: http://localhost:8081
  - service: http_status:404

这将创建一个隧道,将多个主机名路由到服务器上的不同服务,并提供安全的回退(http_status:404)。

流量端到端的传输方式

完整示意图:

flowchart LR
    User --> DNS
    DNS --> Cloudflare
    Cloudflare --> Tunnel
    Tunnel --> ReverseProxy
    ReverseProxy --> App

概念示意图:

sequenceDiagram
    participant User
    participant Cloudflare
    participant Tunnel
    participant Server

    User->>Cloudflare: HTTPS request
    Cloudflare->>Tunnel: Forward request
    Tunnel->>Server: Local HTTP
    Server-->>Tunnel: Response
    Tunnel-->>Cloudflare: Encrypted response
    Cloudflare-->>User: HTTPS response

从外部看,它表现得像普通的 HTTPS 连接,但流量是端到端加密的,在服务器上表现为 localhost 流量。

DNS: 无需手动记录

Cloudflare Tunnel 自动创建所需的 DNS 记录。它会添加一个 CNAME,将你的域指向 Cloudflare 的边缘。运行:

cloudflared tunnel route dns

…就这样!其余由 Cloudflare 处理。

永久运行隧道

首先测试隧道:

cloudflared tunnel run 

当它工作正常时,将其安装为系统服务:

sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared

现在它会在启动时自动启动,失败时会重新启动,并以非 root 用户运行。

添加身份验证

对于任何私有的(管理员面板、仪表盘),我会添加 Cloudflare Access 策略,以在请求到达隧道之前要求身份验证。这确保只有授权用户才能访问这些服务。

Cloudflare Access

Which lets me:

  • 要求登录后才能访问服务
  • 限制电子邮件或身份提供商
  • 在不使用 VPN 的情况下保护内部工具

So from the outside, my dashboard looks public, but in reality it’s locked behind authentication.

我的生产环境设置

这是我实际推荐的布局:

flowchart LR
    User --> Cloudflare
    Cloudflare --> Tunnel
    Tunnel --> ReverseProxy
    ReverseProxy --> Blog
    ReverseProxy --> Dashboard
    ReverseProxy --> Admin

为什么它这么好用?
Cloudflare 负责边缘安全,而我的反向代理负责路由。应用保持在内部且“傻瓜化”,并且没有任何入站端口。

我曾犯的常见错误(让你免于重蹈覆辙)

  • 直接暴露应用而不是通过反向代理
  • 忘记添加 404 ingress 规则
  • 在没有 Access 的情况下运行管理面板
  • 不必要地将服务绑定到 0.0.0.0 而不是 localhost

经验法则:
如果不打算公开,就保持在 localhost。如果需要公开,则使用 Cloudflare Access.

最终思考

虽然 Cloudflare Tunnel 是一个强大的工具,但它并非万灵药。它只是拼图中的一块。将其与其他安全措施(如 Cloudflare Access)结合使用,以确保服务器安全。

不要将其用于以下服务:

  • 对延迟敏感的服务
  • 游戏服务器
  • 完整网络访问(我使用 WireGuard 实现)

然而,对于 HTTP(S) 应用,它是我的默认选择。对于个人服务器和家庭实验室,这是目前可以运行的最简洁的设置之一。

Back to Blog

相关文章

阅读更多 »