使用 Cloudflare Tunnel 和 Traefik 访问部署的 Docker 服务
status
Published
type
Post
slug
self-hosted-service-with-traefik-and-cloudflare-tunnel
date
Feb 10, 2026
tags
Network
Cloudflare
Docker
summary
文章记录了个人自建服务的“古法运维”方案:利用 Traefik 作为本地容器的反向代理和动态服务发现,结合 Cloudflare Tunnel 实现内网穿透和安全访问。
自部署的 Docker 服务用起来很舒心,但数量多了后,端口映射管理,防火墙端口规则,DNS 配置等也很麻烦。
Cloudflare Tunnel 服务,可以在不暴露服务器端口的情况下建立一条服务器连接到 Cloudflare 的隧道,再搭配上 Traefik 来实现各容器服务的服务发现和反向代理,从而可以在公网访问自部署的 Docker 服务。核心逻辑如下:
- 流量入口:用户访问域名 -> Cloudflare 边缘节点 -> Cloudflare Tunnel。
- 穿透层:
cloudflared容器通过隧道将流量拉取到本地 Docker 网络。
- 分发层:流量到达 Traefik,Traefik 根据 HTTP Host 规则(Labels)识别目标容器。
- 应用层:流量最终到达具体的业务容器(如
whoami)。
优势:无需公网 IP,无需在防火墙开启 80/443 端口,自带 SSL 证书管理。
流量路径示意
[ 互联网 (Internet) ] || \/ +---------------------------------------+ | Cloudflare 全球网络 | | (DNS 解析 & 安全防护 & CDN) | +---------------------------------------+ || <== Cloudflare Tunnel ==> (加密隧道) || +--------------||------------------------+ | 宿主机 (Host) | | || | | +----------\/----------+ | | | cloudflared 容器 | | | +----------||----------+ | | || (Docker Network: traefik) | +----------\/----------+ | | | Traefik 容器 | | | | (反向代理/服务发现) | | | +----------||----------+ | | || (路由分发) | | +----------\/----------+ | | | 业务容器 (如 whoami) | | | +----------------------+ | +---------------------------------------+
这套方案用了很久了,但早前都是手动配置了就开始用了。这次服务器被迫重装顺便记录下这种“古法运维”。
现在 LLM / AI Agent 已经很强了,这些内容都能生成或者直接给你配置完成。
这里就简单贴上配置,不做详细操作说明,毕竟 AI 大概干得更好。
Docker 环境配置略去不表。
Traefik 配置
traefik 容器网络配置脚本
network-setup.sh #!/bin/bash NETWORK_NAME=traefik if [ -z $(docker network ls --filter name=^${NETWORK_NAME}$ --format="{{ .Name }}") ] ; then # 创建 Docker 网络 output=$(docker network create ${NETWORK_NAME}); # 检查输出是否为 64 位长度的字符串 if [[ ${#output} -eq 64 ]]; then echo "create docker network for traefik ok" else echo "Network creation failed or output is not 64 characters long." fi fi
执行👆脚本创建一个名为 Traefik 的容器网络。
traefik 容器配置
compose.yamlservices: traefik: container_name: traefik image: traefik restart: always command: - "--global.sendanonymoususage=false" - "--global.checknewversion=false" - "--entrypoints.web.address=:80" - "--api=true" - "--api.dashboard=true" - "--ping=true" - "--log.level=INFO" - "--log.format=common" - "--accesslog=false" - "--providers.docker=true" - "--providers.docker.watch=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.endpoint=unix:///var/run/docker.sock" - "--providers.docker.useBindPortIP=false" - "--providers.docker.network=traefik" ports: - "80:80" # 如本机/局域网也需要访问,则映射;仅走 Tunnel 可不映射 environment: - TZ=Asia/Shanghai labels: - "traefik.enable=true" - "traefik.docker.network=traefik" - "traefik.http.routers.dashboard.rule=Host(`traefik.okhk.net`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.entrypoints=web" # Traefik 管理面板安全认证配置 - "traefik.http.routers.dashboard.middlewares=auth" # echo $(htpasswd -nb admin 你的密码) | sed -e s/\\$/\\$\\$/g - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..." - "traefik.http.middlewares.gzip.compress=true" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro extra_hosts: - "update.traefik.io:127.0.0.1" - "collect.traefik.io:127.0.0.1" - "stats.g.doubleclick.net:127.0.0.1" healthcheck: test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"] interval: 3s retries: 10 logging: driver: "json-file" options: max-size: "5m" networks: - traefik networks: traefik: external: true
自部署服务配置
以 whoami 为例
whoami 容器配置
compose.yamlservices: whoami: image: traefik/whoami container_name: whoami restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.okhk.net`)" - "traefik.http.routers.whoami.entrypoints=web" networks: - traefik networks: traefik: external: true
Traefik 可通过 lables 发现并代理 whoami 服务。
Cloudflare Tunnel 配置
cloudflared 容器配置
compose.yamlservices: cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared restart: always command: tunnel --no-autoupdate run --token $TUNNEL_TOKEN environment: - TZ=Asia/Shanghai env_file: - .env healthcheck: test: ["CMD", "cloudflared", "tunnel", "--metrics", "localhost:20241", "ready"] interval: 10s timeout: 10s retries: 5 start_period: 20s networks: - traefik networks: traefik: external: true
.envTUNNEL_TOKEN=
TUNNEL_TOKEN 获取
登录 Cloudflare Zero Trust 控制台 → Networks -> Tunnels,点击 Create a Tunnel。
可参考 Cloudflare 官网文档:

复制命令中的
--token 后面的长字符串,将其作为环境变量填入上述文件中,启动 cloudflared 容器,建立 Cloudflare Tunnel 链接。Cloudflare Tunnel 路由配置
公网域名 (Public Hostname) | 服务协议 | 内部服务 URL (Service) | 类型说明 |
*.okhk.net | HTTP | http://traefik:80 | 泛域名转发 (推荐) |
whoami.okhk.net | HTTP | http://traefik:80 | 精确匹配 |
如果在 Cloudflare 中配置了泛域名(如
*.okhk.net)指向 http://traefik:80,那么之后新增 Docker 服务时,只需在 Docker Labels 里写好域名,无需再回 Cloudflare 页面操作。如果使用精确域名,则后续每次新增 Docker 服务都需要手动配置域名转发到
http://traefik 。(当然也可以借用一些工具实现根据 Traefik 服务发现情况自动调用 Cloudflare API 添加对应的 tunnel 路由规则,但出于某些原因(懒得整了)就没再弄了

