扩展课 E2
Cloudflare Tunnel:不开端口也能上线
扩展课。第 24 课的做法要开放 80/443 端口、维护证书。Cloudflare Tunnel 换了个思路:服务器主动连到 Cloudflare,外网连接不进你的服务器,只能经过这条隧道。
本课目标
- 理解 Cloudflare Tunnel 和第 24 课做法的区别。
- 创建一条隧道,用 Docker 运行
cloudflared。 - 把访问切换到隧道,关闭 80/443 端口。
先懂概念:从“开门迎客”到“主动打电话”
| 第 24 课:Caddy + 源站证书 | Cloudflare Tunnel | |
|---|---|---|
| 连接方向 | Cloudflare 连到你服务器的 443 端口 | 你的服务器主动连到 Cloudflare |
| 防火墙 | 要开放 80、443 | 只开 22,甚至可以都不开 |
| 证书 | 自己申请、放到服务器上 | 不需要 |
| 依赖 | 只依赖标准的 HTTPS | 依赖 Cloudflare 的隧道服务 |
隧道就像服务器主动给 Cloudflare 打了一个电话并一直不挂:访问者的请求通过这通电话送到服务器,而服务器本身不接任何来电。
跟着做
1. 创建隧道
- 登录 Cloudflare,进入 Zero Trust 控制台(第一次进入需要选择免费套餐,可能要求绑定付款方式但不会扣费)。
- 打开 Networks → Tunnels,点 Create a tunnel,类型选 Cloudflared,名字填
ai-server。 - 安装方式选 Docker。页面会给出一条
docker run ... --token eyJ...命令,只复制--token后面那一长串令牌。
Cloudflare 的界面会调整,菜单名称可能略有不同。
2. 配置公开地址
在隧道的 Public Hostname(公开主机名)里添加一条:
| 字段 | 填写 |
|---|---|
| Subdomain | report |
| Domain | example.com |
| Service Type | HTTP |
| URL | app:3000 |
如果提示 report 已经有一条 DNS 记录,先到 DNS 页面删除第 23 课添加的那条 A 记录,再回来保存。隧道会自动创建新的记录。
3. 在服务器上运行 cloudflared
令牌和 Key 一样敏感,单独放在一个文件里:
cd ~/apps/weekly-report
vim tunnel.env写入一行(换成你的令牌),保存:
TUNNEL_TOKEN=eyJ你的令牌chmod 600 tunnel.env用下面的内容替换 compose.yaml(版本号和你当前用的保持一致):
cat > compose.yaml <<'EOF'
services:
app:
image: 你的用户名/weekly-report:v4
env_file: .env
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
tunnel:
image: cloudflare/cloudflared:latest
command: tunnel --no-autoupdate run
env_file: tunnel.env
restart: unless-stopped
EOF
docker compose up -d --remove-orphans
docker compose ps
docker compose logs tunnel--remove-orphans 会停掉不再写在配置里的 Caddy。日志里出现 Registered tunnel connection 就说明隧道连上了,Cloudflare 控制台里隧道的状态也会变成 Healthy。
4. 关闭 80/443
访问 https://report.example.com,确认能正常打开并要求登录。然后到云服务商的防火墙里删除 TCP 80 和 443 的规则,只保留 22。
再访问一次,依然正常,因为流量走的是隧道。
你应该看到
- 网站照常可用,有锁形图标,需要登录。
- 防火墙只开放 22 端口。
sudo ss -tlnp里没有程序在监听 80、443。
常见问题
访问显示 502 Bad Gateway? 隧道连上了,但找不到周报助手。检查 Public Hostname 的 URL 是否为 app:3000,app 服务是否在运行。
隧道状态是 Down? 看 docker compose logs tunnel,多半是令牌复制不完整,或者 tunnel.env 里等号两边多了空格。
想换回 Caddy 的方式? 按这个顺序:
- 按第 24 课的内容重写
compose.yaml,app的镜像版本保持你现在用的版本,不要退回 v2。 - 运行
docker compose up -d --remove-orphans,停掉tunnel、启动caddy,用docker compose ps确认。 - 在防火墙里重新开放 TCP 80 和 443。
- 在 Cloudflare 里删除隧道的 Public Hostname 和它创建的 DNS 记录,再按第 23 课添加 A 记录(橙色云朵)。
- 访问网站确认正常。
自检
- 我能说出隧道和开放端口两种方式的区别。
- 隧道状态是 Healthy,网站通过隧道访问。
- 防火墙已经关闭 80 和 443。