Traefik 网关部署与维护
使用 Docker Compose 部署 Traefik 作为反向代理网关,搭配 Let's Encrypt 自动 SSL 证书(DNSPod DNS 挑战),为所有 Docker 服务提供统一入口和 HTTPS。
环境
| 项目 | 内容 |
|---|---|
| 服务器 | Ubuntu 24.04 |
| Docker | 29.4.3 |
| Traefik | latest (v3.x) |
| SSL | Let's Encrypt (Production) |
| DNS 挑战 | TencentCloud DNSPod API |
| Dashboard | traefik.zipTako.com(Basic Auth 保护) |
目录结构
~/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
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
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 环境变量
# Traefik 环境变量
# 腾讯云 API 密钥
TENCENTCLOUD_SECRET_ID=AKIDaBmJdjcHjxylX7VhhUEnKZcR3RjpjPsB
TENCENTCLOUD_SECRET_KEY=CBxrZ3KTP8j9To5CIJExTsGWlwyoQoyu部署
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/:
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 证书自动续期,无需人工干预。如需手动管理:
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 标签,定期拉取新版:
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
💾 备份与恢复
核心配置很小,整体备份即可:
# 备份(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 证书和私钥,丢失后需要重新申请(有速率限制)。务必定期备份。
🩺 健康检查
# 检查容器是否正常运行
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\"..."原因:
- 腾讯云 API 密钥无效或权限不足
- DNS 记录传播延迟(尤其 DNSPod 新增子域名后)
解决:检查 .env 中的密钥,或增大 traefik.yml 中的 delaysBeforeCheck(当前未设置,默认即可)
❌ 502 Bad Gateway
Traefik 无法连接到后端服务。
排查步骤:
# 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 只需三步:
Docker Compose 中:
- 将服务加入
traefik网络:networks: - traefik - 添加必要的 labels(参考上面的 dashboard 或下面简单示例)
- 将服务加入
Labels 示例:
yamllabels: - "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"部署:
sudo docker compose up -d
证书会自动通过 Let's Encrypt 申请,无需任何手动操作。