Traefik v3:用 Docker label 自动发现 + 自动 HTTPS 的反代

起因

服务器上跑了 8 个 Docker 容器,每个都想用自己的子域名访问 + HTTPS。
nginx 每加一个服务要改 conf + 申证书 + reload;Caddy 也要改 Caddyfile。
有没有"加新容器自动注册"的方案?

Traefik 是 Go 写的反代,原生支持"从 Docker / K8s / Consul 等动态发现
服务" + Let's Encrypt 自动签证书。加一个容器 = 加一组 label,零配置改动。

解决方案

1. Traefik 容器本身

# /srv/traefik/docker-compose.yml
services:
  traefik:
    image: traefik:v3.1
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      # Traefik dashboard (内网可见)
      - "127.0.0.1:8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
    networks:
      - web

networks:
  web:
    external: true

创建共享网络:

docker network create web

2. traefik.yml

api:
  dashboard: true
  insecure: true   # 仅 127.0.0.1 暴露所以可以 true

entryPoints:
  web:
    address: ':80'
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: ':443'

providers:
  docker:
    exposedByDefault: false   # 容器必须显式 enable 才被 routing
    network: web

certificatesResolvers:
  le:
    acme:
      email: [email protected]
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web
      # 想用 DNS-01 + Cloudflare:
      # dnsChallenge:
      #   provider: cloudflare
      #   delayBeforeCheck: 0

log:
  level: INFO

accessLog: {}

启动:

docker compose up -d

3. 加业务容器:只加 label,不改 traefik

/srv/myapp/docker-compose.yml

services:
  myapp:
    image: myorg/myapp:latest
    restart: unless-stopped
    networks:
      - web
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.myapp.rule=Host(`myapp.example.com`)'
      - 'traefik.http.routers.myapp.entrypoints=websecure'
      - 'traefik.http.routers.myapp.tls.certresolver=le'
      - 'traefik.http.services.myapp.loadbalancer.server.port=3000'

networks:
  web:
    external: true
docker compose up -d

Traefik 一秒内:

  • 发现新容器
  • 加路由 myapp.example.com → myapp:3000
  • 通过 HTTP-01 challenge 自动签 Let's Encrypt 证书
  • 80 自动跳 443

curl https://myapp.example.com/ 立刻可用。

4. 多服务批量

services:
  api:
    image: api:latest
    networks: [web]
    labels:
      - traefik.enable=true
      - traefik.http.routers.api.rule=Host(`api.example.com`)
      - traefik.http.routers.api.entrypoints=websecure
      - traefik.http.routers.api.tls.certresolver=le
      - traefik.http.services.api.loadbalancer.server.port=8000

  blog:
    image: ghost:5
    networks: [web]
    labels:
      - traefik.enable=true
      - traefik.http.routers.blog.rule=Host(`blog.example.com`)
      - traefik.http.routers.blog.entrypoints=websecure
      - traefik.http.routers.blog.tls.certresolver=le
      - traefik.http.services.blog.loadbalancer.server.port=2368

  uptime:
    image: louislam/uptime-kuma:1
    networks: [web]
    labels:
      - traefik.enable=true
      - traefik.http.routers.up.rule=Host(`up.example.com`)
      - traefik.http.routers.up.entrypoints=websecure
      - traefik.http.routers.up.tls.certresolver=le
      - traefik.http.services.up.loadbalancer.server.port=3001

3 个服务,3 套 label,3 个域名。零修改 traefik 配置。

5. 加中间件:basic auth / IP 白名单 / rate limit

label 里声明 + 应用:

labels:
  - traefik.enable=true
  - traefik.http.routers.admin.rule=Host(`admin.example.com`)
  - traefik.http.routers.admin.entrypoints=websecure
  - traefik.http.routers.admin.tls.certresolver=le
  - traefik.http.routers.admin.middlewares=auth,ratelimit
  - 'traefik.http.middlewares.auth.basicauth.users=alice:$$apr1$$abc...'
  - 'traefik.http.middlewares.ratelimit.ratelimit.average=10'
  - 'traefik.http.middlewares.ratelimit.ratelimit.burst=20'
  - traefik.http.services.admin.loadbalancer.server.port=8000

basic auth password 用 htpasswd -nb alice secret 生成(注意 $
YAML 里 escape 成 $$)。

6. dashboard

打开 SSH tunnel:

ssh -L 8080:localhost:8080 server
# 浏览器:http://localhost:8080

看到所有 router / service / middleware,状态可视化。

效果

  • 加新容器从"改 nginx + certbot + reload + DNS 配 + …" 收敛到
    "docker-compose up,加 5 行 label"
  • 8 个服务的反代配置文件总长 < 100 行(之前 nginx 200+ 行 / 4 个
    vhost 文件)
  • 证书自动续期,不再有 "忘续期 → 网站红框" 事故
  • 加 / 删服务无 traefik 重启
  • dashboard 一眼看到所有 route 状态

与 nginx / Caddy / HAProxy 对比

Traefik nginx Caddy HAProxy
Docker 自动发现 ✅ 原生 ❌(需第三方) 一定程度
自动 HTTPS ❌(需 certbot)
K8s ingress
性能 极高 极高
配置 YAML / labels nginx 语法 Caddyfile HAProxy 语法
学习曲线

容器化场景选 Traefik;静态站 / 极致性能选 nginx;混合简单场景 Caddy。

踩过的坑

  1. network: web 不指定 Traefik 不知道连哪个 net:容器在多个网络
    时 Traefik 不确定走哪个。一定在 traefik.yml 里 providers.docker.network: web
    或每个服务 label 写 traefik.docker.network=web

  2. acme.json 权限不对:Traefik 要求 600。chmod 600 letsencrypt/acme.json

  3. HTTP-01 challenge 失败:80 端口被占 / 路由器没转发。检查
    curl -I http://myapp.example.com/.well-known/acme-challenge/test
    能不能到 Traefik 容器。

  4. 生产 dashboard 暴露公网api.insecure=true 千万别开公网。
    要外网访问 dashboard 加 router + auth middleware 包起来。

  5. Let's Encrypt 频率限制:测试期间反复重启 + 反复申证书会被
    LE rate limit。dev 用 acme.caServer: https://acme-staging-v02.api.letsencrypt.org/directory
    测试,跑通后切回生产 CA。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。