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.json:cp 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