docker容器环境下反向代理配置方案

分类:建站教程

什么是 Docker 反向代理自动发现

传统反向代理如 Nginx,每新增一个服务都需要手动编辑配置文件、申请证书、重启服务。在容器频繁增删的 Docker 环境中,这种手动流程成为运维负担。

Docker 反向代理自动发现是指反向代理工具能够实时监听 Docker 事件,当容器启动时自动创建路由规则,容器停止时自动移除。你只需要在容器上添加几行标签,代理就会自动完成路由注册和 HTTPS 证书申请。

这种模式的核心价值是:添加新服务只需 docker compose up,无需修改任何代理配置。

三大自动发现方案对比

特性 Traefik Caddy + caddy-docker-proxy nginx-proxy
配置方式 Docker 标签 Docker 标签 环境变量
自动 HTTPS 内置 ACME 内置(默认开启) 需配合 acme-companion
学习曲线 中等 低 低
仪表盘 内置 Dashboard 无 无
中间件 丰富(30+) 有限 基础
内存占用 ~30-50 MB ~15-20 MB ~10-15 MB
适用场景 复杂微服务、Kubernetes 简单部署、快速上线 固定服务、传统架构

Traefik:容器原生的自动发现王者

Traefik 是专为容器环境设计的云原生反向代理,Docker 自动发现是它的核心能力。它监听 Docker socket,读取容器标签,自动创建路由和申请证书。

核心优势

  • 标签驱动:在容器上添加 traefik.* 标签即可定义路由规则
  • 自动 HTTPS:内置 ACME 客户端,自动从 Let's Encrypt 申请和续期证书
  • 实时生效:容器启动即路由就绪,无需重启或重载
  • 中间件丰富:支持认证、限流、CORS、熔断等 30+ 中间件

部署 Traefik

# /srv/traefik/docker-compose.yml
services:
  traefik:
    image: traefik:v3.7
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # 只读挂载 Docker socket,用于自动发现
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
    networks:
      - web

# 预先创建的外部网络
networks:
  web:
    external: true

静态配置文件 traefik.yml:

api:
  dashboard: true
  insecure: true  # 仅内网可访问

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

providers:
  docker:
    exposedByDefault: false  # 安全:必须显式启用
    network: web

certificatesResolvers:
  le:
    acme:
      email: your@email.com
      storage: /acme.json
      httpChallenge:
        entryPoint: web

添加业务服务

# /srv/myapp/docker-compose.yml
services:
  myapp:
    image: myorg/myapp:latest
    restart: unless-stopped
    networks:
      - web
    labels:
      # 启用 Traefik 处理
      - 'traefik.enable=true'
      # 路由规则:匹配域名
      - 'traefik.http.routers.myapp.rule=Host(`myapp.example.com`)'
      # 使用 HTTPS 入口
      - '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 会在秒级内完成:检测新容器、创建路由规则、申请 HTTPS 证书、配置 HTTP 跳转。

添加中间件

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'
  # Basic Auth 配置
  - 'traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xxx'
  # 限流配置:每秒 10 请求
  - 'traefik.http.middlewares.ratelimit.ratelimit.average=10'
  - 'traefik.http.services.admin.loadbalancer.server.port=8080'

Caddy + caddy-docker-proxy:极简自动发现方案

如果你追求 最简单的自动 HTTPS,Caddy 是最佳选择。配合 caddy-docker-proxy 插件,它也能实现 Docker 自动发现。

核心优势

  • 自动 HTTPS 默认开启:无需任何证书配置
  • 配置极简:3 行标签即可完成反向代理
  • HTTP/3 默认支持:无需额外配置

部署 Caddy + caddy-docker-proxy

# /srv/caddy/docker-compose.yml
services:
  caddy:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"  # HTTP/3
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
    environment:
      - DOMAIN=example.com
    networks:
      - web

networks:
  web:
    external: true

volumes:
  caddy_data:

构建包含 caddy-docker-proxy 的镜像:

# Dockerfile
FROM caddy:2.11-alpine
RUN xcaddy build --with github.com/lucaslorentz/caddy-docker-proxy/v2

Caddyfile 配置:

# /srv/caddy/Caddyfile
{
    email your@email.com
}

:80 {
    reverse_proxy caddy-docker-proxy:2015
}

添加业务服务

# /srv/myapp/docker-compose.yml
services:
  myapp:
    image: myorg/myapp:latest
    restart: unless-stopped
    networks:
      - web
    labels:
      # Caddy 自动发现只需 3 行
      - "caddy=app.example.com"
      - "caddy.reverse_proxy={{upstreams 3000}}"

networks:
  web:
    external: true

Caddy 会自动:检测新容器、创建路由、申请 Let's Encrypt 证书、配置 HTTP/HTTPS 跳转。整个过程无需手动干预。

nginx-proxy:基于环境变量的经典方案

nginx-proxy 是最早的 Docker 自动发现反向代理,通过环境变量配置路由。

核心优势

  • 架构简单:基于成熟的 Nginx
  • 环境变量配置:对传统运维友好
  • 社区成熟:问题解决方案丰富

部署 nginx-proxy + acme-companion

# /srv/nginx-proxy/docker-compose.yml
services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:1.10
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - certs:/etc/nginx/certs
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
    networks:
      - proxy
    restart: always

  acme-companion:
    image: nginxproxy/acme-companion
    container_name: nginx-proxy-acme
    volumes_from:
      - nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - acme:/etc/acme.sh
    environment:
      - DEFAULT_EMAIL=your@email.com
    networks:
      - proxy
    restart: always

networks:
  proxy:
    external: true

volumes:
  certs:
  vhost:
  html:
  acme:

添加业务服务

# /srv/myapp/docker-compose.yml
services:
  myapp:
    image: myorg/myapp:latest
    restart: unless-stopped
    expose:
      - "3000"  # 注意是 expose 不是 ports
    environment:
      - VIRTUAL_HOST=app.example.com
      - VIRTUAL_PORT=3000
      - LETSENCRYPT_HOST=app.example.com
    networks:
      - proxy

networks:
  proxy:
    external: true

性能对比

根据 2026 年基准测试,三种方案在 Docker 环境下的表现:

方案 HTTP 请求/秒 HTTPS 请求/秒 P99 延迟 内存占用
Traefik ~28,000 ~22,000 3.8 ms 30-50 MB
Caddy ~30,000 ~24,000 3.2 ms 15-20 MB
nginx-proxy ~45,000 ~32,000 2.1 ms 10-15 MB

注意:性能差异对绝大多数应用无影响。选择应基于功能需求而非性能基准。

选型决策矩阵

场景 推荐方案 理由
复杂微服务架构 Traefik 丰富的中间件和路由规则
Kubernetes 环境 Traefik 原生 K8s 支持
简单项目快速上线 Caddy 最简配置,自动 HTTPS
固定服务、传统架构 nginx-proxy 成熟稳定,文档丰富
资源受限环境 Caddy 内存占用最低

常见问题与解决方案

1. 502 Bad Gateway

原因:反向代理无法连接到后端容器

解决:检查容器是否加入正确的 Docker 网络,确认端口配置正确

2. HTTPS 证书申请失败

原因:80 端口未开放或被占用

解决:确保 80 端口可从公网访问,检查防火墙规则

3. 容器重启后路由丢失

原因:Docker socket 未正确挂载

解决:确认 /var/run/docker.sock:/var/run/docker.sock:ro 已配置

最佳实践

  1. 使用外部网络:将反向代理和业务服务放在同一个外部 Docker 网络
  2. 限制暴露范围:设置 exposedByDefault: false,只代理显式启用的容器
  3. 保护 Docker socket:使用 :ro 只读挂载,或使用 Docker Socket Proxy
  4. 定期检查证书:虽然自动续期,但仍需监控证书状态
  5. 使用标签管理:所有配置通过标签声明,便于版本控制和审计