UCloud + Dokploy + Cloudflare Tunnel 安全访问配置
TL;DR
隐藏 UCloud 公网入口,所有流量只走 Cloudflare Tunnel,不再直接暴露服务器 IP。
用户
└─ Cloudflare (HTTPS)
└─ Cloudflare Tunnel
└─ cloudflared 容器(--network host)
└─ Traefik / Dokploy(HTTP localhost:80)
├─ admin-xxx
├─ api-xxx
└─ dokploy 后台
最终效果:
- 服务器 80 / 443 对公网关闭
- 应用照常通过原域名访问
- SSH 只开放自己的 IP
域名规划
| 域名 | 用途 |
|---|---|
admin-xxx.your-domain.com | 前端 / 管理页面 |
api-xxx.your-domain.com | 后端 API |
dokploy.your-domain.com | Dokploy 管理后台 |
步骤一:创建 Cloudflare Tunnel
路径:Zero Trust → Networks → Tunnels → Create Tunnel
Tunnel 名称:ucloud-1,运行环境选 Docker。
Cloudflare 生成的原始命令不够用,改用以下命令启动:
docker run -d \
--name cloudflared \
--restart unless-stopped \
--network host \
cloudflare/cloudflared:latest \
tunnel --no-autoupdate run --token 你的完整token
--network host必须加。 不加的话localhost:80指向的是 cloudflared 容器自己,而不是宿主机的 Traefik。
验证是否运行:
docker ps | grep cloudflared
docker logs -f cloudflared # 看到 "Connection established" 即成功
步骤二:配置 Tunnel 路由
路径:Zero Trust → Networks → Tunnels → ucloud-1 → Public Hostnames
三个域名全部指向同一个目标:
| 域名 | 目标 |
|---|---|
admin-xxx.your-domain.com | http://localhost:80 |
api-xxx.your-domain.com | http://localhost:80 |
dokploy.your-domain.com | http://localhost:80 |
Traefik 会根据 Host 请求头自动路由,不需要填容器端口或公网 IP。
步骤三:修改 Cloudflare DNS
删除旧 A 记录,改为 CNAME 指向 Tunnel:
| 类型 | 名称 | 目标 |
|---|---|---|
| CNAME | admin-xxx | <TunnelID>.cfargotunnel.com |
| CNAME | api-xxx | <TunnelID>.cfargotunnel.com |
| CNAME | dokploy | <TunnelID>.cfargotunnel.com |
CNAME 目标格式是
TunnelID.cfargotunnel.com(不是 tunnel 名称ucloud-1)。如果提示
DNS record operation failed: HTTP 400,说明旧 A 记录还存在,先删再手动建 CNAME。
步骤四:配置 Dokploy 域名
关键原则: Cloudflare 负责外部 HTTPS,Dokploy 内部关闭 HTTPS,Tunnel 走 HTTP。
若 Dokploy 开启 HTTPS,Traefik 会把 HTTP 请求 308 跳转到 HTTPS,导致 Tunnel 链路反复重定向。
admin-xxx
| 字段 | 值 |
|---|---|
| Domain | admin-xxx.your-domain.com |
| Container Port | 80 |
| HTTPS | 关闭 |
# 验证
curl -I -H "Host: admin-xxx.your-domain.com" http://127.0.0.1
# 期望:HTTP/1.1 200 OK
api-xxx
| 字段 | 值 |
|---|---|
| Domain | api-xxx.your-domain.com |
| Container Port | 3000(填服务实际监听端口) |
| HTTPS | 关闭 |
# 根路由 404 不代表错误,测试真实接口路径
curl -i -H "Host: api-xxx.your-domain.com" http://127.0.0.1/真实接口路径
dokploy
| 字段 | 值 |
|---|---|
| Domain | dokploy.your-domain.com |
| Container Port | 3000(Dokploy 默认) |
| HTTPS | 关闭 |
步骤五:SSL/TLS 设置
Cloudflare 全局模式保持 Full strict(完整严格),不要改成 Flexible 或关闭。
⚠️ 警告:不要给 Dokploy 加 Cloudflare Access
不要给 dokploy.your-domain.com 配置 Cloudflare Access 保护。
CI/CD(GitHub Actions 等)部署时需要直接调用 Dokploy API,Cloudflare Access 会拦截所有自动化请求,导致部署全部失败。
Dokploy 本身有用户名 + 密码保护,只要服务器 80 / 443 对公网关闭,风险已经很低。
步骤六:关闭 UCloud 公网端口
确认三个域名均可正常访问后,在 UCloud 安全组删除以下规则:
| 协议 | 端口 | 来源 | 操作 |
|---|---|---|---|
| TCP | 80 | 0.0.0.0/0 | 删除 |
| TCP | 443 | 0.0.0.0/0 | 删除 |
| TCP | 3389 | 0.0.0.0/0 | 删除 |
| ICMP | — | 0.0.0.0/0 | 删除 |
| TCP | 22 | 你的公网 IP/32 | 保留 |
SSH 加固(修改后 sudo systemctl restart ssh):
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
关闭密码登录前,必须先确认密钥登录可用,否则会把自己锁在服务器外。
常用检查命令
# Tunnel 状态
docker ps | grep cloudflared
docker logs -f cloudflared
# 本机路由测试
curl -I -H "Host: admin-xxx.your-domain.com" http://127.0.0.1
curl -I -H "Host: api-xxx.your-domain.com" http://127.0.0.1
# 外部访问测试
curl -I https://admin-xxx.your-domain.com
curl -I https://api-xxx.your-domain.com
curl -I https://dokploy.your-domain.com
# 服务器状态
sudo ss -lntp
docker ps
docker logs --tail=100 容器名
注意事项速查
| # | 规则 |
|---|---|
| 1 | 不要给任何域名加 Cloudflare Access(会拦截 CI/CD) |
| 2 | Tunnel 路由统一指向 http://localhost:80 |
| 3 | Dokploy 应用内部 HTTPS 关闭 |
| 4 | Cloudflare 全局 SSL/TLS 保持 Full strict |
| 5 | DNS 删除指向 UCloud IP 的 A 记录 |
| 6 | UCloud 安全组关闭 80 / 443 |
| 7 | cloudflared 容器保持运行,使用 --network host |