在VPS上使用Docker Compose安装Traefik反向代理

当您在单个VPS上运行多个Docker容器时,最关键的挑战就是:如何将传入流量正确路由到对应的容器?传统解决方案(如Nginx)要求手动编辑配置文件并在每次添加新服务时重新加载,这对于快速迭代的微服务环境来说效率低下。Traefik是一款现代云原生反向代理,它革新了这一工作流程。Traefik能够直接读取Docker标签、自动发现容器、自动从Let's Encrypt申请SSL证书,以及在不中断其他服务的情况下即时添加新的子域名和服务。与传统反向代理相比,Traefik大幅降低了运维复杂度,特别适合需要频繁部署和更新微服务的现代开发团队。

为什么选择Traefik而非Nginx?

Nginx作为一款成熟稳定的反向代理,在高度定制化的场景下仍然有其优势。但对于以Docker为核心的现代部署环境,Traefik的自动化和动态特性使其成为更优选择。Nginx需要你为每个新服务或子域名手动编辑配置文件并执行reload命令,而Traefik通过Docker标签自动识别新容器,从而实现真正的零停机部署。

Traefik的核心理念是"基础设施即代码"——通过容器标签定义路由规则,而不是在配置文件中硬编码。这使得每个容器都"自描述"其路由需求,大大提高了代码的可维护性和可读性。

系统要求与前置条件

第一步 — 创建Docker共享网络

Traefik和所有需要路由的容器必须连接到同一个Docker网络。这个网络不仅处理网络通信,还允许容器通过服务名相互通信。

docker network create traefik-net

验证网络创建成功:

docker network ls | grep traefik-net

第二步 — 创建Traefik静态配置文件

静态配置定义Traefik的核心行为——如何监听端口、如何处理SSL证书、如何读取Docker标签等。此配置在容器启动时加载,运行时不可更改。

mkdir -p ~/traefik && cd ~/traefik
cat > traefik.yml << 'EOF'
api:
  dashboard: true           # 启用仪表板(需要通过标签配置认证)
  insecure: false           # 禁用不安全API访问

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https     # 自动将HTTP重定向到HTTPS

  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]    # 替换为您的有效邮箱
      storage: /acme.json               # 证书存储位置
      httpChallenge:
        entryPoint: web                 # 使用HTTP-01验证方式

providers:
  docker:
    exposedByDefault: false            # 仅暴露带"traefik.enable=true"标签的容器
    network: traefik-net               # 使用我们创建的网络

log:
  level: INFO                           # 日志级别(INFO/DEBUG/WARN/ERROR)
EOF

第三步 — 编写Docker Compose配置

Docker Compose文件定义Traefik容器本身的配置,包括它如何挂载socket、how to handle volumes,以及仪表板认证设置。

cat > docker-compose.yml << 'EOF'
version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro    # Docker socket(只读)
      - ./traefik.yml:/traefik.yml:ro                    # 静态配置(只读)
      - ./acme.json:/acme.json                            # SSL证书存储
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      # 仪表板路由配置
      - "traefik.http.routers.dashboard.rule=Host(\`traefik.example.com\`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=auth"
      # Basic Auth认证(下一步生成)
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xxxxxxxx$$xxxxxxxxxx"

networks:
  traefik-net:
    external: true
EOF

生成Basic Auth密码

仪表板需要身份验证保护。使用Apache工具生成密码哈希:

# 安装Apache工具包
sudo apt install apache2-utils -y

# 生成密码哈希(将yourpassword替换为您的实际密码)
htpasswd -nb admin yourpassword
# 输出示例:admin:$apr1$rMS5zfjj$Xst3nF1BQvZLZJBONvNpy0

# 复制整个输出,粘贴到docker-compose.yml中
# 重要:docker-compose中的$字符需要双重转义,每个$替换为$$
# 示例:$apr1$ 变成 $$apr1$$
# 完整标签:
# - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$rMS5zfjj$$Xst3nF1BQvZLZJBONvNpy0"

第四步 — 初始化SSL证书存储

acme.json文件存储Let's Encrypt颁发的所有SSL证书。Traefik对文件权限有严格要求——必须是600权限,否则会拒绝启动。

touch acme.json
chmod 600 acme.json

# 验证权限设置
ls -l acme.json
# 应输出:-rw------- 1 user user 0 Jun 10 12:00 acme.json

第五步 — 启动Traefik容器

现在启动Traefik并监控日志,确保它成功启动并开始监听请求。

# 在后台启动Traefik
docker compose up -d

# 查看启动日志(Ctrl+C退出)
docker logs traefik -f

# 预期日志输出:
# msg="Starting Traefik"
# msg="Creating provider aggregator"
# msg="Starting provider Docker"
# msg="Listening on :80"
# msg="Listening on :443"

🔒 SSL证书申请:首次启动时,Traefik会为您在docker-compose.yml中配置的仪表板域名请求SSL证书。此过程通常需要1-2分钟。查看日志中是否出现 msg="Obtaining certificate" 表示申请进行中。如果遇到 error="acme: urn:acme:error:dns",说明DNS还未完全传播,请等待几分钟后重启Traefik容器。

为新Web应用配置动态路由

Traefik的核心优势在于其动态配置能力。不需要修改Traefik本身的配置,仅通过Docker标签就能添加新的应用。下面是添加WordPress容器的完整示例。

示例:部署WordPress容器

# 创建WordPress的compose文件(文件名:docker-compose-wp.yml)
version: "3.8"

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress-blog
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: secure_password
      WORDPRESS_TABLE_PREFIX: wp_
    networks:
      - traefik-net
    depends_on:
      - wordpress-db
    labels:
      # 启用Traefik路由
      - "traefik.enable=true"
      # 定义规则:匹配blog.example.com域名
      - "traefik.http.routers.wp.rule=Host(\`blog.example.com\`)"
      # 使用HTTPS入口点
      - "traefik.http.routers.wp.entrypoints=websecure"
      # 使用我们配置的Let's Encrypt解析器
      - "traefik.http.routers.wp.tls.certresolver=letsencrypt"
      # 指定应用的内部端口(WordPress默认80)
      - "traefik.http.services.wp.loadbalancer.server.port=80"

  wordpress-db:
    image: mysql:8.0
    container_name: wordpress-db
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: secure_password
    volumes:
      - wp-db-data:/var/lib/mysql
    networks:
      - traefik-net

networks:
  traefik-net:
    external: true

volumes:
  wp-db-data:

启动WordPress:

docker compose -f docker-compose-wp.yml up -d

# Traefik会自动:
# 1. 检测新的wordpress容器
# 2. 读取标签配置
# 3. 为blog.example.com向Let's Encrypt请求SSL证书
# 4. 配置路由规则
# 5. 在DNS传播后,blog.example.com流量自动转发到WordPress

# 验证路由已配置(访问Traefik仪表板)
# https://traefik.example.com/dashboard/
# 使用之前设置的admin用户名和密码登录

常用中间件配置

限速 — 防止API滥用

限速中间件防止单个客户端发送过多请求。配置平均请求速率和突发容量。

labels:
  - "traefik.enable=true"
  # 限速配置:平均100请求/分钟,允许50个请求的突发
  - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
  - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
  - "traefik.http.middlewares.ratelimit.ratelimit.period=1m"
  # 应用到应用的路由
  - "traefik.http.routers.myapp.middlewares=ratelimit"
  - "traefik.http.routers.myapp.rule=Host(\`api.example.com\`)"
  - "traefik.http.routers.myapp.entrypoints=websecure"
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  - "traefik.http.services.myapp.loadbalancer.server.port=3000"

IP白名单 — 限制访问来源

仅允许特定IP或IP范围访问,用于保护管理面板或内部工具。

labels:
  - "traefik.enable=true"
  # IP白名单配置
  - "traefik.http.middlewares.ipallow.ipallowlist.sourcerange=203.0.113.0/24,10.0.0.0/8"
  # 添加信任的代理IP,处理X-Forwarded-For头
  - "traefik.http.middlewares.ipallow.ipallowlist.ignorexforwardedfor=false"
  # 应用到管理面板
  - "traefik.http.routers.admin.middlewares=ipallow"
  - "traefik.http.routers.admin.rule=Host(\`admin.example.com\`)"
  - "traefik.http.routers.admin.entrypoints=websecure"
  - "traefik.http.routers.admin.tls.certresolver=letsencrypt"
  - "traefik.http.services.admin.loadbalancer.server.port=8080"

重定向 — www到非www域名

使用正则表达式中间件规范化URL结构,改进SEO。

labels:
  - "traefik.enable=true"
  # 重定向规则:www.example.com → example.com
  - "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www\\.(.+)"
  - "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://$${1}"
  - "traefik.http.middlewares.www-redirect.redirectregex.permanent=true"
  # 应用到主应用
  - "traefik.http.routers.main.middlewares=www-redirect"
  - "traefik.http.routers.main.rule=Host(\`example.com\`,\`www.example.com\`)"
  - "traefik.http.routers.main.entrypoints=websecure"
  - "traefik.http.routers.main.tls.certresolver=letsencrypt"
  - "traefik.http.services.main.loadbalancer.server.port=80"

Traefik与Nginx Proxy Manager对比

在选择反向代理时,理解不同方案的优劣势很重要。下表比较了Traefik和Nginx Proxy Manager的主要特性。

功能 Traefik Nginx Proxy Manager
容器自动发现✅ 通过Docker标签❌ 需要手动添加
SSL自动更新✅ 内置支持✅ 内置支持
Web管理界面仪表板(只读模式)完整Web UI(可编辑)
中间件丰富度✅ 非常丰富受限
Kubernetes支持✅ 原生Ingress❌ 不支持
学习曲线陡峭(需要理解YAML/标签)平缓(直观的Web UI)
最适合DevOps工程师/开发团队寻求简便UI的初级用户

故障排查与常见问题

问题:SSL证书未申请

如果您的应用无法通过HTTPS访问,首先检查Traefik是否成功请求了证书。

# 查看日志中的ACME相关信息
docker logs traefik 2>&1 | grep -i "acme\|certificate\|error"

# 检查acme.json中是否有证书数据
cat acme.json | python3 -m json.tool | head -50

# 常见原因:
# 1. DNS未完全传播 — 等待5-15分钟后重试
# 2. 端口80被防火墙阻止 — 运行 sudo ufw allow 80
# 3. Let's Encrypt API在维护中 — 查看 https://letsencrypt.org/status/
# 4. 邮箱地址无效 — 检查traefik.yml中的email字段

问题:容器无法通过Traefik访问

如果特定应用无法访问,检查容器是否正确连接到traefik-net网络并有有效的标签。

# 验证容器连接的网络
docker inspect wordpress-blog | grep -A10 "Networks"

# 输出应显示:
# "traefik-net": {
#   "IPAMConfig": null,
#   "Links": null,
#   "Aliases": null,
#   "NetworkID": "xxxxxxxx"
#   "EndpointID": "xxxxxxxx"
#   "Gateway": "172.19.0.1"
#   "IPAddress": "172.19.0.2"

# 验证Traefik是否识别了容器标签
docker inspect wordpress-blog | grep -i traefik

# 如果容器标签正确但Traefik未识别,尝试重启Traefik
docker restart traefik

# 等待30秒并查看日志
docker logs traefik -f | head -20

问题:仪表板无法访问或显示403错误

# 验证Basic Auth配置是否正确
docker compose config | grep -A3 "basicauth"

# 如果密码哈希不完整,重新生成
htpasswd -nb admin newpassword

# 编辑docker-compose.yml中的标签,使用新哈希
# 然后重建并重启Traefik
docker compose up -d --force-recreate

安全性最佳实践

1. 保护Traefik仪表板

仪表板应该始终受到身份验证保护,不要直接暴露到互联网。除了Basic Auth,还可以考虑:

2. 定期更新Traefik版本

# 检查新版本
docker pull traefik:latest

# 更新docker-compose.yml中的image版本
# image: traefik:v3.1  (或最新版本)

# 重启服务
docker compose down && docker compose up -d

3. 监控日志和指标

# 定期检查错误日志
docker logs traefik | grep -i error

# 设置日志级别为DEBUG以获得更多信息
# 在traefik.yml中修改:log.level = DEBUG

性能优化建议

启用连接池

对于高流量应用,启用HTTP连接重用可显著提高性能。

labels:
  - "traefik.http.services.myapp.loadbalancer.healthcheck.path=/health"
  - "traefik.http.services.myapp.loadbalancer.healthcheck.interval=10s"
  - "traefik.http.services.myapp.loadbalancer.healthcheck.timeout=3s"

多容器负载均衡

如果同一服务有多个实例,Traefik会自动在它们之间负载均衡。

# 启动3个WordPress实例
docker compose -f docker-compose-wp.yml up -d --scale wordpress=3

# Traefik会自动检测所有3个容器并均匀分配流量

与Docker Swarm集成

如果您计划在未来扩展到多服务器部署,Traefik可以无缝迁移到Docker Swarm,无需改变配置范式。

# 初始化Docker Swarm
docker swarm init

# 部署Traefik作为service
docker service create --name traefik \
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
  --publish 80:80 \
  --publish 443:443 \
  traefik:v3.0 \
  --providers.docker.swarmmode=true \
  --entrypoints.web.address=:80 \
  --entrypoints.websecure.address=:443

需要VPS来运行Traefik + Docker?

AsiaGB VPS提供Linux完整root权限和SSD存储,开箱即可运行Docker Compose与Traefik容器编排。高性能VPS主机,99% Uptime保证。

查看VPS套餐

查看泰国VPS主机全部套餐 →