Sub2API + Cloudflare Tunnel 一体化部署教程
目标:用 Docker Compose 部署 sub2api + PostgreSQL + Redis + cloudflared,宿主机不暴露任何业务端口。公网访问只走 Cloudflare Tunnel。
1. 准备 Cloudflare Tunnel
前提:
- 你的域名已经添加到 Cloudflare,并且 DNS 由 Cloudflare 托管。
- 服务器能主动访问公网。Cloudflare Tunnel 是出站连接,不需要在服务器安全组或防火墙里放行入站
80、443、8080、5432、6379。
在英文版 Cloudflare Zero Trust 控制台创建 Tunnel:
- 进入
Zero Trust -> Networks -> Connectors -> Cloudflare Tunnels。- 如果你的控制台还是旧版入口,可能显示为
Zero Trust -> Networks -> Tunnels。
- 如果你的控制台还是旧版入口,可能显示为
- 点击
Create a tunnel。 Select your connector选择Cloudflared。- 输入 Tunnel 名称,例如
sub2api,然后保存。 - 在安装命令页面选择
Docker,复制命令里--token后面的长字符串,后面填到.env的CLOUDFLARED_TOKEN。
CLOUDFLARED_TOKEN 等同于这个 Tunnel 的连接凭据,不要发给别人,也不要提交到 Git 仓库。
Public Hostname 在 Tunnel connector 连上后配置:
- 启动本文后面的 Docker Compose。
- 回到 Cloudflare Tunnel 页面,确认 connector 变成
Healthy。 - 进入这个 Tunnel 的
Published applications。- 有些界面会显示为
Public Hostnames或Published Application Routes。
- 有些界面会显示为
- 点击
Add a public hostname,填写:Subdomain:例如apiDomain:你的域名,例如example.comPath:留空Service Type:选择HTTPURL/Service:填sub2api:8080- 其他高级选项保持默认即可,不需要开启
No TLS Verify,因为这里到源站是普通 HTTP。
如果你的界面只有一个完整 Service 输入框,也可以直接填 http://sub2api:8080。
注意:这里的 sub2api 是 Docker Compose 内部服务名,不是公网域名,也不是 127.0.0.1。Cloudflare Tunnel 和 Sub2API 在同一个 Docker 网络里,所以 cloudflared 可以用服务名访问 sub2api:8080。
2. 创建部署目录
mkdir -p /opt/sub2api-stack
cd /opt/sub2api-stack
mkdir -p volumes/sub2api-postgres volumes/sub2api-redis volumes/sub2api-data
3. 写入 docker-compose.yml
这个 Compose 没有 ports: 配置,所以不会在宿主机暴露 8080、5432、6379 或其他业务端口。
4. 写入 .env
建议这样生成随机值后替换 .env 里的 change-me-*:
JWT_SECRET 和 TOTP_ENCRYPTION_KEY 必须固定保存。不要留空,也不要每次重建时重新生成,否则会导致已有登录会话失效,已绑定的 2FA 也可能失效。
5. 启动
正常状态应类似:
sub2api-db Up ... healthy
sub2api-redis Up ... healthy
sub2api Up ... healthy
cloudflared Up ...
6. 验证
因为没有暴露宿主机端口,所以不要用宿主机 curl http://127.0.0.1:8080/ 判断是否成功。
用容器内检查:
也可以检查更轻量的健康接口:
用公网域名检查:
把 api.example.com 替换成你在 Cloudflare Public Hostname 里配置的域名。
7. 更新
只更新 Sub2API:
更新全部镜像:
8. 常用排障
查看 Sub2API 日志:
查看 Cloudflare Tunnel 日志:
确认 Cloudflare Tunnel 能在容器网络内访问 Sub2API:
如果公网域名访问失败,但上面的容器网络检查成功,优先检查 Cloudflare Tunnel 的 Public Hostname 是否配置为: