本文以"家庭宽带没有公网 IPv4"为前提,使用 Cloudflare Tunnel 将家里的 Web/API 服务安全地发布到公网。
**隐私说明:**本文示例全部使用虚构域名、占位 IP、占位令牌和通用项目名,未包含真实域名、真实公网地址、Cloudflare 账号信息、Tunnel Token 或任何个人敏感信息。
一、为什么家里的服务器没有公网 IP 也能访问?
传统的公网访问通常是:
text
用户浏览器
↓
公网 IP:443
↓
家庭路由器端口转发
↓
家里的服务器
↓
Nginx / Spring Boot / Docker
但很多家庭宽带没有可直接入站访问的公网 IPv4,可能处于运营商 CGNAT 后面。这种情况下,即使你知道家里的出口地址,也通常无法直接从公网访问家里的服务器。
Cloudflare Tunnel 换了一种思路:不要求公网主动"打进"家里,而是让家里的 cloudflared 主动向 Cloudflare 建立出站连接。 Cloudflare 官方文档将其描述为 outbound-only 连接,因此不需要给家庭服务器提供公网 IP,也不需要开放家庭路由器的入站端口。
最终链路可以变成:
text
用户
↓
https://api.example.com
↓
Cloudflare
↓
Cloudflare Tunnel
↓
家里服务器 cloudflared
↓
Nginx / Docker / Spring Boot
Cloudflare Tunnel 支持公开发布 HTTP/HTTPS 应用,也支持其他协议;对于公开 Web/API 场景,最适合使用"Published application"路由。
二、准备条件
开始之前准备好下面几个东西:
- 一个 Cloudflare 账号。
- 一个已经托管到 Cloudflare 的域名。
- 家里的服务器可以正常访问互联网。
- 家里的 Web/API 服务已经在本机监听,例如
127.0.0.1:8080或某个 Docker 网络中的服务。
Cloudflare 官方当前的 Tunnel 入门文档要求:Cloudflare 账号、一个托管在 Cloudflare 上的域名,以及一台可以访问互联网并运行 cloudflared 的服务器。
如果家庭网络对出站连接有限制,还需要确保服务器能够访问 Cloudflare Tunnel 所需的网络端口;官方文档特别提到可以检查 7844 端口的连通性。
三、为什么推荐"远程管理型 Tunnel"
Cloudflare Tunnel 有本地管理和远程管理两种方式。
现在的家庭服务器 / Docker 部署场景,我更推荐远程管理型 Tunnel(remotely-managed tunnel):
- Tunnel 配置存放在 Cloudflare。
- 可以直接在 Cloudflare Dashboard 中管理 Hostname 和 Service。
- Docker 部署非常方便。
- 以后换机器、迁移服务时,不必重新维护一堆本地配置文件。
Cloudflare 当前文档也明确建议大多数场景使用 remotely-managed tunnel,并且针对 Docker 推荐这种方式。
四、第一步:把域名交给 Cloudflare 管理
进入 Cloudflare Dashboard,把你的域名添加进去,并按照 Cloudflare 给出的要求修改域名注册商处的 Nameserver。
注意:
"域名注册商"和"DNS 服务商"不是一回事。
域名可以继续在原注册商购买,但 DNS 权威解析可以交给 Cloudflare。
完成后,在 Cloudflare 的域名页面确认 DNS 已经生效。
五、第二步:创建 Cloudflare Tunnel
进入 Cloudflare Dashboard:
text
Networking
→ Tunnels
→ Create Tunnel
输入一个 Tunnel 名称,例如:
text
home-server
名字只是为了方便管理,不需要和域名一致。
Cloudflare 当前 Dashboard 创建 Tunnel 的流程就是在 Networking → Tunnels 中创建新的 Tunnel,然后选择服务器操作系统并获取安装命令。
六、第三步:在家里的服务器运行 cloudflared
假设家里的服务器是 Linux,并且已经安装 Docker。
Cloudflare Dashboard 创建 Tunnel 后,会给出对应的安装命令。对于 Docker,官方当前推荐的运行方式类似:
bash
docker run cloudflare/cloudflared:latest \
tunnel --no-autoupdate run --token <TUNNEL_TOKEN>
这里的 <TUNNEL_TOKEN> 是 Cloudflare Dashboard 给当前 Tunnel 生成的令牌。
不要把真实 Token 发到博客、Git 仓库、截图或者聊天记录里。
如果 Token 泄露,应立即在 Cloudflare 侧进行处理,而不是继续使用泄露的凭据。
Cloudflare 官方文档给出的 Docker 运行方式也是通过 tunnel run --token 启动 remotely-managed tunnel。
更适合长期运行的 Docker Compose
如果希望让 cloudflared 跟随服务器自动启动,可以使用 Docker Compose:
yaml
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run --token ${CF_TUNNEL_TOKEN}
然后在 .env 中保存:
env
CF_TUNNEL_TOKEN=这里填写真实Token
并确保 .env 不提交到 Git:
gitignore
.env
如果你把整个项目提交到 Git,建议进一步使用密码管理器、Secrets 或 CI/CD Secret 来保存 Tunnel Token,而不是把它写进 compose 文件。
七、第四步:确认 Tunnel 已经连接
启动后回到 Cloudflare Dashboard:
text
Networking
→ Tunnels
→ 你的 Tunnel
如果服务器上的 cloudflared 已经正常连上 Cloudflare,Tunnel 应该显示为正常/健康状态。
Linux 上也可以先看容器日志:
bash
docker logs -f cloudflared
如果启动失败,优先检查:
bash
docker ps
docker logs cloudflared
以及服务器能否正常访问互联网。
八、第五步:发布 API 域名
假设你家里的 Spring Boot API 在服务器本机的:
text
http://127.0.0.1:8080
你希望公网访问:
text
https://api.example.com
在 Cloudflare Dashboard 里进入对应 Tunnel,然后:
text
Routes
→ Add route
→ Published application
然后填写:
text
Hostname:
api.example.com
Service:
http://localhost:8080
保存即可。
Cloudflare 的 Published application 本质上就是建立一个"公网 Hostname → 本地 Service"的映射,例如 app.example.com → http://localhost:8080。
如果你的服务不在 cloudflared 所在容器里
这里是 Docker 部署最容易踩坑的地方。
如果 cloudflared 自己是一个 Docker 容器,那么:
text
http://localhost:8080
这里的 localhost 指向的是cloudflared 容器自己,不是宿主机。
如果你的 Spring Boot 运行在另一个 Docker 容器里,更推荐让两个容器进入同一个 Docker Network,然后直接通过容器服务名访问,例如:
text
http://backend:8080
例如:
yaml
services:
backend:
image: your-backend:latest
restart: unless-stopped
cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel --no-autoupdate run --token ${CF_TUNNEL_TOKEN}
depends_on:
- backend
这样 Cloudflare Tunnel 可以直接把请求交给 Docker 网络中的 backend:8080。
九、如果前面还有 Nginx
如果你的家用服务器原本就已经使用 Nginx 做反向代理,那么结构可以设计成:
text
Internet
↓
api.example.com
↓
Cloudflare
↓
Cloudflare Tunnel
↓
cloudflared
↓
Nginx
↓
Spring Boot
例如 Nginx:
nginx
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
然后 Cloudflare Tunnel 只需要指向 Nginx:
text
http://nginx:80
这种方式的好处是:
- Cloudflare 负责公网入口。
- Tunnel 负责穿透。
- Nginx 负责域名和反向代理。
- Spring Boot 继续只承担业务接口。
如果后面有多个服务,会比较好管理。
十、DNS 需要怎么配置?
这里和传统公网 IP 的方式不一样。
传统情况可能是:
text
A
api
203.0.113.10
但使用 Cloudflare Tunnel 后,不需要把家庭公网 IP 填进 A 记录。
通过 Cloudflare Dashboard 创建 Published application 后,Cloudflare 会为这个 hostname 建立对应的 Tunnel 路由 / DNS 记录。
因此,最重要的不是"我家有没有公网 IP",而是:
text
api.example.com
↓
Cloudflare Tunnel
↓
家里的 cloudflared
十一、这样之后还需要路由器端口转发吗?
通常不需要。
传统内网穿透经常要求:
text
路由器 443
↓
服务器 443
Cloudflare Tunnel 的工作方式是家里服务器主动向外建立连接,所以通常不需要做公网入站端口映射,也不要求你拥有公网 IPv4。
因此家庭路由器可以保持:
text
不开放 80
不开放 443
不开放其他业务端口
对于降低家庭网络暴露面是有帮助的。
十二、HTTPS 证书怎么办?
这也是 Cloudflare Tunnel 比单纯 FRP 更省事的地方。
用户访问:
text
https://api.example.com
HTTPS 可以由 Cloudflare 在公网侧处理。
你家里的服务甚至可以继续使用:
text
http://backend:8080
当然,如果你的内部链路还有额外安全要求,也可以继续使用 HTTPS。
Cloudflare Tunnel 的公网请求首先到 Cloudflare 网络,再通过 Tunnel 转到 origin;Cloudflare 在这个过程中可以应用其 CDN、WAF、Bot Management 和 DDoS 防护能力。
十三、一个完整的家庭服务器架构
如果家里服务器后面以后要跑很多东西,可以设计成:
text
Internet
│
https://api.example.com
│
▼
┌───────────────┐
│ Cloudflare │
│ DNS / TLS / │
│ WAF / DDoS │
└───────┬───────┘
│
Cloudflare Tunnel
│
▼
┌──────────────────┐
│ cloudflared │
└────────┬─────────┘
│
Docker Network
│
┌────────────┴────────────┐
│ │
▼ ▼
Nginx other service
│
▼
Spring Boot API
以后还可以继续增加:
text
api.example.com → Spring Boot
admin.example.com → 管理后台
home.example.com → 家庭网页
nas.example.com → NAS Web
但不要因为 Tunnel 能转发,就把所有内部服务毫无保护地公开到公网。 管理后台、NAS、Docker 管理页面、数据库、MQTT 管理接口等,应根据实际需求增加访问控制。
十四、Cloudflare Tunnel 与 FRP 怎么选?
如果已经有一台公网 VPS,FRP 依然很有价值:
text
公网 VPS
↑
FRP
↑
家庭服务器
它的优势是控制力强、协议灵活,尤其适合你自己掌握公网中转服务器的场景。
Cloudflare Tunnel 则更适合:
text
家里没有公网 IP
+ 已经有 Cloudflare 域名
+ 主要发布 HTTP/HTTPS 网站/API
+ 不想维护一台公网中转服务器
Cloudflare Tunnel 现在官方明确支持无公网 IP 的出站连接模式,并且 Tunnel 本身可以建立多条长期连接来提高可靠性。
十五、不要使用 Quick Tunnel 代替正式部署
Cloudflare 还提供 Quick Tunnel,例如:
bash
cloudflared tunnel --url http://localhost:8080
它会生成一个随机的 trycloudflare.com 地址,非常适合临时测试。
但正式项目不建议长期使用 Quick Tunnel。Cloudflare 当前文档明确把 Quick Tunnels 定位为开发/测试用途,并且存在并发请求等限制。正式应用应该创建 Named / remotely-managed Tunnel。
十六、安全方面最容易犯的错误
1. 把 Tunnel Token 提交到 Git
错误:
yaml
command: tunnel run --token eyJ......真实Token
然后直接提交 GitHub/Gitee。
正确:
yaml
command: tunnel run --token ${CF_TUNNEL_TOKEN}
Token 放到 .env、Secrets 或其他安全凭据存储中。
2. 把数据库直接暴露出去
不要把:
text
mysql:3306
redis:6379
直接发布成公网 hostname。
数据库应该继续留在内网,仅让后端 API 暴露出去。
3. 把 Docker 管理端口公开
例如 Docker API、Portainer、数据库管理页面、路由器后台等,应该谨慎处理。
4. 误以为"用了 Cloudflare 就不用认证了"
Cloudflare Tunnel 负责的是连接与入口,不代表业务本身自动安全。
例如:
text
/api/login
/api/user
/api/order
仍然应该做好认证、授权、限流、参数校验等。
十七、排查问题时的顺序
当 https://api.example.com 打不开时,建议按照下面的链路一层层排查:
第 1 层:Cloudflare Tunnel 是否在线
bash
docker ps | grep cloudflared
bash
docker logs cloudflared
第 2 层:Tunnel 能不能访问内部服务
在服务器上测试:
bash
curl http://127.0.0.1:8080
如果 Spring Boot 在 Docker 中,则测试实际 Docker 服务地址。
第 3 层:检查容器网络
例如:
bash
docker exec -it cloudflared sh
然后测试目标服务是否可达。
第 4 层:检查 Cloudflare Published application
确认:
text
Hostname:
api.example.com
Service:
http://backend:8080
是否填写正确。
第 5 层:检查应用层
例如:
bash
curl -I https://api.example.com
如果能得到 HTTP 状态码,说明 DNS / Tunnel / 应用链路至少已经走通了一部分。
十八、最终推荐方案
对于"家庭服务器 + 没有公网 IP + 有自己的域名 + Docker + Spring Boot"这个场景,一个非常实用的方案是:
text
公网
│
▼
api.example.com
│
▼
Cloudflare
│
▼
Cloudflare Tunnel
│
(出站连接)
│
▼
家里的服务器
│
cloudflared
│
Docker 网络
│
▼
Nginx
│
▼
Spring Boot
核心特点:
- 不要求家庭宽带有公网 IPv4。
- 不需要家庭路由器做 443 入站端口转发。
- 自己的域名可以继续使用。
- HTTPS 公网入口由 Cloudflare 处理。
- Docker 部署方便。
- 后面可以继续挂多个子域名。
对于个人项目、家庭服务器、个人 API、博客、Demo 网站,这套方案非常适合。
十九、参考资料
本文以 Cloudflare 2026 年官方文档为依据:
- Cloudflare Tunnel Overview:https://developers.cloudflare.com/tunnel/
- Tunnel Setup:https://developers.cloudflare.com/tunnel/setup/
- Create a remotely-managed tunnel:https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/
- Tunnel Routing:https://developers.cloudflare.com/tunnel/routing/
- Tunnel Configuration:https://developers.cloudflare.com/tunnel/configuration/
- Local-managed Tunnel:https://developers.cloudflare.com/tunnel/advanced/local-management/
二十、个人部署时的脱敏检查清单
发布文章、上传 Git 仓库或截图之前,建议检查:
text
[ ] 真实域名 → 替换为 example.com
[ ] 真实公网 IP → 替换为 203.0.113.0/24 示例地址
[ ] 内网真实 IP → 替换为 192.168.x.x
[ ] Cloudflare Tunnel Token → 完全删除
[ ] API Key → 完全删除
[ ] Cloudflare Account ID → 删除或替换
[ ] Zone ID → 删除或替换
[ ] 路由器公网信息 → 删除
[ ] 个人邮箱 → 删除或替换
[ ] SSH 地址 / 端口 / 密码 → 删除
[ ] Docker Registry 地址 → 删除
[ ] 项目真实仓库地址 → 删除
原则:宁可让示例不完整,也不要为了"教程能复制"把真实凭据和真实基础设施信息贴出去。