没有公网IP?十分钟用 Cloudflare Tunnel 把本地服务暴露到公网,自带 HTTPS 和 CDN

1. 前言

你有没有遇到过这种情况:

自己在本地 Linux 服务器上搭了个好玩的 Docker 服务(比如之前说的 Fast Note Sync、Jellyfin、Homer 等),想在外面用手机或者公司电脑访问,结果发现——没有公网 IP。

以前大家的解法无非就是几种:

  1. FRP 内网穿透——得额外买一台有公网 IP 的 VPS 做中转,多花一份钱
  2. DDNS + 端口映射——得有公网 IP,运营商还不一定给,而且端口裸奔风险大
  3. Tailscale / ZeroTier 组网——免费好用,但需要在每台设备上都装客户端,家里人用起来不方便

今天分享另一种方案:Cloudflare Tunnel

它有多香?

  • 不需要公网 IP,也不需要端口映射
  • 自带 HTTPS 证书,Cloudflare 自动帮你签好
  • DDoS 防护、CDN 加速,全白嫖
  • 配合自己的域名,访问体验跟正常网站完全一样
  • 客户端(cloudflared)超轻量,Docker 或直接装都行

用大白话说就是:Cloudflare 帮你搭了一条专属隧道,你本地的服务通过这条隧道连到 Cloudflare 的边缘节点,用户直接访问你的域名即可,全程加密,全程免费。

架构上看是这样的:

用户浏览器 ─→ https://note.tqo.cc ─→ Cloudflare 边缘节点
                                              │
                                         加密隧道
                                              │
                                     cloudflared(本机)
                                              │
                                     http://localhost:9000
                                              │
                                       你的 Docker 服务

我自己现在就是这么用的——本机搭的服务全部走 Cloudflare Tunnel 暴露出去,省了 VPS 的钱,也用不着搞端口映射了。

2. 项目相关地址

3. 搭建环境

在开始之前,你需要准备以下东西:

  • 一台本地 Linux 服务器(Debian / Ubuntu 都行,本教程以 Debian 12 为例)
  • 一个域名,并且域名的 NS 已经托管到 Cloudflare(域名购买参考:Namesilo
  • 确保本地服务器能正常访问网络(能拉取 GitHub 或 Docker 镜像)

关于 Namesilo:上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo 上 6 位数字的 xyz 续费永远都是 0.99 美元 = =)如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些。Namesilo 自带隐私保护,我一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些古老 = =)

域名托管到 Cloudflare

不管你是在 Namesilo、GoDaddy 还是哪里买的域名,先去 Cloudflare 注册账号,添加你的域名,然后把 Namesilo 那边的 NS 记录改成 Cloudflare 分配的四个 NS 地址。

Cloudflare 会扫描你域名的现有 DNS 记录,等它扫完之后,到 Namesilo 那边把 NS 改成 Cloudflare 的就行。等个几分钟到几小时不等,Cloudflare 那边会显示「Active」,就可以了。

4. 安装 cloudflared

cloudflared 是 Cloudflare 的隧道客户端,负责在你的本地服务器和 Cloudflare 边缘节点之间建立长连接。

4.1 直接安装

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -O /usr/local/bin/cloudflared

chmod +x /usr/local/bin/cloudflared

cloudflared version

如果看到版本号输出,说明安装成功了。

4.2 用 Docker 安装(可选)

如果你不想在宿主机直接装二进制,也可以用 Docker 跑:

docker run cloudflare/cloudflared version

不过本文教程以二进制安装为例,更方便配置 systemd 服务。

5. 授权登录

在开始创建隧道之前,cloudflared 需要先跟你的 Cloudflare 账号建立授权关系。

cloudflared tunnel login

会打印出一个链接,类似这样:

Open the following URL in your browser to authenticate:
https://dash.cloudflare.com/argotunnel?callback=xxxxxx

复制链接,在浏览器打开,登录你的 Cloudflare 账号,选择你托管在 Cloudflare 的域名(比如 tqo.cc),点击授权。

授权成功后,凭据会自动保存在 /root/.cloudflared/cert.pem

6. 创建隧道

6.1 新建隧道

cloudflared tunnel create my-tunnel

注意:my-tunnel 可以改成你想要的名字,比如 fast-note-synchome-server 等,后续配置中会用到这个名字。

成功后,会看到类似这样的输出:

Created tunnel my-tunnel with id d6c8bca2-0b93-48d4-9997-e8deb673caf2

这个 UUID 就是隧道的唯一标识,后面配置会用到。同时会在 /root/.cloudflared/ 目录下生成一个 <UUID>.json 的凭证文件。

可以查看已创建的隧道列表:

cloudflared tunnel list

6.2 配置 DNS 路由

隧道建好了,需要把你的域名指向这个隧道:

cloudflared tunnel route dns my-tunnel note.example.com

记得把 note.example.com 换成你自己的域名。

这条命令会在 Cloudflare DNS 中自动添加一条 CNAME 记录,指向隧道地址。不需要去 Cloudflare 面板手动加。

7. 编写配置文件

隧道需要一个配置文件来告诉 cloudflared,哪些域名走哪条路由。

创建配置目录:

mkdir -p /etc/cloudflared

写入配置文件:

vim /etc/cloudflared/config.yml
tunnel: d6c8bca2-0b93-48d4-9997-e8deb673caf2
credentials-file: /root/.cloudflared/d6c8bca2-0b93-48d4-9997-e8deb673caf2.json

ingress:
  - hostname: note.example.com
    service: http://localhost:9000
  - service: http_status:404

注意:把 tunnel 后面的 UUID 换成你刚才创建隧道时生成的 UUID,credentials-file 路径也要对应修改。

配置说明:

参数说明
tunnel隧道 UUID
credentials-file凭证文件路径
ingress路由规则列表
- hostname: xxx匹配的域名
service: http://localhost:9000转发到本地哪个服务
- service: http_status:404兜底规则,不匹配的域名返回 404

如果你有多个服务要暴露,可以在 ingress 下面加多条规则,比如:

ingress:
  - hostname: note.example.com
    service: http://localhost:9000
  - hostname: hermes.example.com
    service: http://localhost:8787
  - hostname: self.example.com
    service: http://10.0.0.9:8088
  - service: http_status:404

注意:ingress 规则是从上到下匹配的,匹配到就停止,所以最下面一定要有个兜底规则。

8. 测试运行

先别急着装系统服务,我们先前台跑一下,看看能不能通:

cloudflared tunnel run my-tunnel

看到类似这样的日志,说明隧道连接成功:

+ Trying to connect to Cloudflare Edge...
+ Registered tunnel connection
+ Connection registered

这时打开浏览器,访问你配置的域名(比如 https://note.example.com),看看能不能正常访问你的本地服务。

如果访问不了,先看看传输出错的原因是什么:

  1. 检查本地服务端口是否正常运行:curl http://localhost:9000
  2. 检查 ingress 配置里的 hostname 和端口是否正确
  3. 检查域名解析是否生效:nslookup note.example.com

测试没问题之后,按 Ctrl+C 停掉前台进程。

9. 安装 systemd 服务(开机自启)

作为正经服务,我们要让它后台运行、开机自启。

cloudflared service install

systemctl start cloudflared

systemctl enable cloudflared

systemctl status cloudflared

看到 active (running) 就说明服务正常运行了。

以后系统重启,cloudflared 会自动跟着启动,不用每次都手动去执行。

10. 日常操作

10.1 添加新服务到已有隧道

如果你原来已经有一个隧道,想再加一个域名暴露新服务,只需要两步:

第一步,DNS 路由指向隧道:

cloudflared tunnel route dns my-tunnel new-service.example.com

第二步,编辑配置文件,在 ingress 下面加一条新规则:

vim /etc/cloudflared/config.yml
ingress:
  - hostname: note.example.com
    service: http://localhost:9000
  - hostname: new-service.example.com
    service: http://localhost:新端口
  - service: http_status:404

第三步,重启 cloudflared:

systemctl restart cloudflared

搞定。

10.2 查看隧道状态

cloudflared tunnel list          # 列出所有隧道
systemctl status cloudflared     # 查看服务状态
journalctl -u cloudflared -f     # 查看实时日志

10.3 更新 cloudflared

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -O /usr/local/bin/cloudflared

chmod +x /usr/local/bin/cloudflared

systemctl restart cloudflared

10.4 卸载 cloudflared

systemctl stop cloudflared
systemctl disable cloudflared

rm -f /usr/local/bin/cloudflared

rm -rf /root/.cloudflared

rm -rf /etc/cloudflared

# 清理 systemd 残留
systemctl reset-failed cloudflared

可以卸载得很干净。

11. 使用体验

实际用下来感受:

  • 和「有公网 IP + Nginx 反代」的体验几乎没区别,浏览器直接输域名就能访问
  • HTTPS 证书 Cloudflare 自动搞定,不用担心证书过期
  • 延迟方面,因为多走了一层 Cloudflare 边缘节点,比直连会多几十毫秒,但日常使用感受不太出来
  • 适合 Web 服务(WebUI、API、网页),不适合传大文件或对延迟敏感的实时服务
  • 同一个隧道可以挂多个域名,管理起来非常方便

12. 常见问题及注意点

12.1 HTTP 还是 HTTPS?

配置里写 service: http://localhost:9000 即可,因为隧道本身是加密的,Cloudflare 到用户端是 HTTPS,cloudflared 到你的本地服务走内网 HTTP 就够了。

12.2 我的本地服务需要 HTTPS 吗?

不需要。Cloudflare 到用户端走 HTTPS(Cloudflare 自动签证书),Cloudflare 到你的 cloudflared 走加密隧道,cloudflared 到你的本地服务走 HTTP 就够了。

12.3 DNS 记录冲突

如果用 cloudflared tunnel route dns 报错,说 code 1003,大概率是 Cloudflare 面板上已经有一条相同域名的 DNS 记录。先去 Cloudflare 面板把那旧记录删了,再重新运行命令。

12.4 配置文件路径冲突

cloudflared service install 默认读取 /etc/cloudflared/config.yml。如果你手动指定了其他路径,或者配了两个地方的配置不一致,可能导致服务启动失败。

确保 /etc/cloudflared/config.yml/root/.cloudflared/ 下的凭证文件路径一致即可。

12.5 标签含义

ingress 规则从上到下匹配,匹配到就停止,所以最下面一定要有个兜底规则(http_status:404),否则不匹配的域名访问时会报错。

13. 对比其他穿透方案

方案费用公网 IPHTTPS延迟适用场景
Cloudflare Tunnel免费不需要自带较低Web 服务
FRP 内网穿透需买 VPS需要中转机需自己配较高TCP/UDP 全协议
Tailscale / ZeroTier免费不需要自带较低个人设备组网
DDNS + 端口映射免费需要需自己配最低单个服务直连

14. 结尾

Cloudflare Tunnel 算是我最近用得最爽的工具之一了,没有公网 IP 也能让本地的服务在外面稳定访问,而且还免费、自带 HTTPS,省心不少。

祝大家用得开心,有问题可以去 Cloudflare 官方文档看看,也可以在评论区互相交流探讨。

参考资料

© Copyright Notice
THE END
喜欢就支持一下吧
Likes9赞赏 Share
评论 Be the First to Comment
欢迎您留下宝贵的见解!
Submit

Nickname

Cancel
NicknameEmojiCodeImageQuick reply

    No comments yet