Skip to content

Traefik 网关部署与维护

使用 Docker Compose 部署 Traefik 作为反向代理网关,搭配 Let's Encrypt 自动 SSL 证书(DNSPod DNS 挑战),为所有 Docker 服务提供统一入口和 HTTPS。

环境

项目内容
服务器Ubuntu 24.04
Docker29.4.3
Traefiklatest (v3.x)
SSLLet's Encrypt (Production)
DNS 挑战TencentCloud DNSPod API
Dashboardtraefik.zipTako.com(Basic Auth 保护)

目录结构

bash
~/docker/traefik/
├── docker-compose.yml          # 服务定义
├── traefik.yml                 # 静态配置(入口、证书、Provider)
├── .env                        # 腾讯云 API 密钥
├── config/
   └── dynamic.yml             # 动态配置(非 Docker 路由规则)
├── acme.json                   # Let's Encrypt 证书存储(chmod 600)
└── logs/
    ├── traefik.log             # 运行日志
    └── access.log              # 访问日志

docker-compose.yml

yaml
services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik
    ports:
      - "80:80"           # HTTP → 301 跳转到 HTTPS
      - "443:443"         # HTTPS
      - "8080:8080"       # Dashboard(内网访问)
    environment:
      - TENCENTCLOUD_SECRET_ID=${TENCENTCLOUD_SECRET_ID}
      - TENCENTCLOUD_SECRET_KEY=${TENCENTCLOUD_SECRET_KEY}
      - DOCKER_API_VERSION=1.40
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro  # Docker 服务发现
      - ./traefik.yml:/traefik.yml:ro                  # 静态配置
      - ./config:/config                                # 动态配置
      - ./acme.json:/acme.json                          # SSL 证书存储
      - ./logs:/var/log/traefik                         # 日志
    labels:
      # Dashboard 路由
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.zipTako.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.tls=true"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.middlewares=dashboard-auth"
      # 基础认证(密码用 htpasswd 生成)
      - "traefik.http.middlewares.dashboard-auth.basicauth.users=ziptako:$$2y$$05$$5kIU2egVmHQXbgc6FOrQruw27op9JuKfHbIF1NE7UUE5/TGgjtHRG"

networks:
  traefik:
    name: traefik
    driver: bridge

静态配置 traefik.yml

yaml
api:
  dashboard: true
  debug: false

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

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false       # 默认不暴露,需要手动 label 开启
    watch: true
    network: traefik
  file:
    directory: /config
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: "zzp-email@qq.com"
      storage: /acme.json
      caServer: https://acme-v02.api.letsencrypt.org/directory
      dnsChallenge:
        provider: tencentcloud
        # 环境变量:TENCENTCLOUD_SECRET_ID + TENCENTCLOUD_SECRET_KEY

log:
  level: INFO
  filePath: /var/log/traefik/traefik.log

accessLog:
  filePath: /var/log/traefik/access.log

.env 环境变量

bash
# Traefik 环境变量
# 腾讯云 API 密钥
TENCENTCLOUD_SECRET_ID=AKIDaBmJdjcHjxylX7VhhUEnKZcR3RjpjPsB
TENCENTCLOUD_SECRET_KEY=CBxrZ3KTP8j9To5CIJExTsGWlwyoQoyu

部署

bash
cd ~/docker/traefik

# 首次部署前创建日志目录
mkdir -p logs config

# 创建 acme.json 并设置权限
touch acme.json
chmod 600 acme.json

# 启动
docker compose up -d

# 检查状态
sudo docker compose ps
sudo docker compose logs traefik --tail 20

# 访问 Dashboard(需基础认证)
# https://traefik.zipTako.com/dashboard/

维护

🪵 日志管理

Traefik 日志分为两类,均输出到 ~/docker/traefik/logs/

bash
cd ~/docker/traefik

# 查看实时日志
sudo docker compose logs traefik --tail 50 -f

# 查看运行日志文件
tail -100 logs/traefik.log

# 查看访问日志文件
tail -100 logs/access.log

# 统计各域名访问量
awk '{print $9}' logs/access.log | sort | uniq -c | sort -rn

# 查看 4xx/5xx 错误
grep -E ' [45][0-9]{2} ' logs/access.log | tail -20

# 日志轮转(日志只保留 7 天,每天切割)
# 可以用 logrotate 或直接 crontab
cat > /tmp/traefik-logrotate.conf << 'EOF'
/home/ubuntu/docker/traefik/logs/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}
EOF
sudo cp /tmp/traefik-logrotate.conf /etc/logrotate.d/traefik
rm /tmp/traefik-logrotate.conf

使用 copytruncate 而非 create,Traefik 不需要重启。

🔐 证书管理

Let's Encrypt 证书自动续期,无需人工干预。如需手动管理:

bash
cd ~/docker/traefik

# 查看证书信息(acme.json 是 JSON 格式)
sudo python3 -c "
import json
with open('acme.json') as f:
    data = json.load(f)
for cert in data.get('letsencrypt', {}).get('Certificates', []):
    print(f\"Domain: {cert.get('domain', {})}\")
    print(f\"Subject: {cert.get('certificate', '')[:50]}...\")
" 2>/dev/null || echo "acme.json 格式解析失败,可能不是直接 JSON"

# 查看证书到期时间
sudo docker compose exec traefik traefik healthcheck --ping

# 强制手动续期(重启 Traefik 触发)
sudo docker compose restart traefik

# 切换到 Staging 环境测试(改 traefik.yml 中的 caServer)
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory
# sudo docker compose restart traefik
# 测试完成后改回 Production 并重启

⚠️ 注意acme.json 的权限必须是 600(仅拥有者读写),否则 Traefik 拒绝启动。如果误改了权限,执行 chmod 600 acme.json 后重启。

🔄 容器更新

Traefik 使用 latest 标签,定期拉取新版:

bash
cd ~/docker/traefik

# 拉取最新镜像
sudo docker compose pull

# 对比版本变动
sudo docker compose logs --tail=5 traefik

# 重启应用新版本
sudo docker compose up -d --force-recreate

# 清理旧镜像
sudo docker image prune -f

更新前建议先备份 acme.jsoncp acme.json acme.json.bak

💾 备份与恢复

核心配置很小,整体备份即可:

bash
# 备份(traefik.yml + acme.json + config/)
tar czf ~/traefik-backup-$(date +%Y%m%d).tar.gz \
  -C ~/docker/traefik \
  traefik.yml docker-compose.yml .env config/ acme.json

# 恢复
tar xzf ~/traefik-backup-20260512.tar.gz -C ~/docker/traefik/
chmod 600 ~/docker/traefik/acme.json
cd ~/docker/traefik && sudo docker compose up -d

acme.json 是核心资产——里面存着所有域名的 SSL 证书和私钥,丢失后需要重新申请(有速率限制)。务必定期备份。

🩺 健康检查

bash
# 检查容器是否正常运行
sudo docker ps --filter name=traefik --format "{{.Names}} {{.Status}}"

# 检查 Traefik 健康端点
sudo docker compose exec traefik traefik healthcheck --ping

# 检查证书状态(acme.json 大小)
ls -lh ~/docker/traefik/acme.json  # 通常几十 KB

# 测试 SSL 证书
curl -svI https://traefik.zipTako.com 2>&1 | grep -i "SSL\|certificate"

# 测试已配置的站点
curl -skI https://wiki.zipTako.com | head -5

故障排查

❌ acme.json 权限错误

level=error msg="Unable to read ACME storage file /acme.json: open /acme.json: permission denied"

解决chmod 600 ~/docker/traefik/acme.json && sudo docker compose restart traefik

❌ DNS 挑战失败

level=error msg="Unable to obtain ACME certificate for domains \"xxx.zipTako.com\"..."

原因

  1. 腾讯云 API 密钥无效或权限不足
  2. DNS 记录传播延迟(尤其 DNSPod 新增子域名后)

解决:检查 .env 中的密钥,或增大 traefik.yml 中的 delaysBeforeCheck(当前未设置,默认即可)

❌ 502 Bad Gateway

Traefik 无法连接到后端服务。

排查步骤

bash
# 1. 确认后端服务容器在运行
sudo docker ps --filter name=vitepress

# 2. 确认服务在同一 network
sudo docker network inspect traefik | grep -E '"Name"|"Container"'

# 3. 确认端口 label 正确
sudo docker inspect vitepress | grep -A3 traefik

# 4. 登录 Traefik 容器手动测试连通性
sudo docker compose exec traefik wget -qO- http://vitepress:4173 | head -5

❌ "This host is not allowed"

VitePress Dev 模式下,请求被 Vite 拒绝——检查 vite.server.allowedHosts 配置。

对接新服务的流程

新服务接入 Traefik 只需三步:

  1. Docker Compose 中:

    • 将服务加入 traefik 网络:networks: - traefik
    • 添加必要的 labels(参考上面的 dashboard 或下面简单示例)
  2. Labels 示例

    yaml
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.xxx.rule=Host(`xxx.zipTako.com`)"
      - "traefik.http.routers.xxx.tls=true"
      - "traefik.http.routers.xxx.tls.certresolver=letsencrypt"
      - "traefik.http.services.xxx.loadbalancer.server.port=PORT"
  3. 部署sudo docker compose up -d

证书会自动通过 Let's Encrypt 申请,无需任何手动操作。

参考链接

Powered by VitePress + Bun + Hermes Agent