Traefik指南:65k星容器原生反向代理,自动发现服务+自动HTTPS

项目:traefik/traefik | 星数:65409 | 语言:Go | 协议:MIT | GitHub仓库

更新日期:2026-10-30 · 作者:CodeArts 编辑部

容器时代为什么该换掉手写 Nginx 配置

我最早的反向代理是 Nginx 加一份手写的配置文件。那套东西在虚拟机上跑了三年没出过问题,直到我开始用 Docker Compose 频繁起停服务。每加一个服务,就要改 conf、reload、再记一下端口,漏掉一次就是 502。Traefik 解决的就是这个痛点:它监听 Docker 事件,容器起来自动注册路由,容器删掉自动摘除,配置写在容器标签里,跟着服务走。

65409 星、MIT 协议、Go 单二进制。除了 Docker,它还支持 Kubernetes IngressRoute、Swarm、Consul、etcd 等多种 provider,以及自动申请 Let's Encrypt 证书。它不是"Nginx 的更快替代品",而是"面向动态环境的代理"——这一点决定了它的取舍。

它的路由模型

概念含义例子
EntryPoint监听端口web:80 / websecure:443
Router匹配规则,决定请求去哪Host(`api.example.com`)
Service实际的后端地址与负载均衡容器 IP + 内部端口
Middleware请求前后处理BasicAuth / 限流 / 重定向

四层概念记住了,后面所有配置都是它们的组合。我见过最多的问题是 Router 匹配不上——多半是 EntryPoint 没配、或者规则里的反引号被 YAML 吃掉了。

最小可用:docker-compose 版本

services:
  traefik:
    image: traefik:v3
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --api.dashboard=true
      - --api.insecure=true
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"

--providers.docker.exposedbydefault=false 这行必须加。默认是 true,会让所有容器自动暴露到公网,包括你没打算公开的数据库和管理面板。

挂载 docker.sock 的安全代价

挂 /var/run/docker.sock 等于把宿主机 root 权限交给了 Traefik 容器——拿到这个 socket 就能起一个特权容器挂载宿主根目录。这是 Traefik 用得最广也最常被忽略的风险。

做法安全度复杂度
直接挂 docker.sock低最低
挂 docker.sock 的只读代理(docker-socket-proxy)中低
用 etcd/Consul 作为配置源,不下发 socket高中
Kubernetes 用 IngressRoute,由 CRD 驱动高中

个人服务器图省事直接挂没问题,但至少要把 Traefik 容器本身的权限收紧,别让它同时还有别的挂载。生产环境务必走 socket-proxy 或 CRD 路线。

自动 HTTPS:一行标签搞定

command:
  - --entrypoints.websecure.address=:443
  - --certificatesresolvers.le.acme.email=you@example.com
  - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
  - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
labels:
  - "traefik.http.routers.whoami.tls.certresolver=le"

注意 acme.json 的文件权限必须是 600,否则 Traefik 启动时会直接报错退出——这是新手最常见的启动失败原因。另外申请配额有限,调试期间反复删容器会导致 Let's Encrypt 限流,调试阶段建议先用自签证书或 --certificatesresolvers.le.acme.caserver 指向 staging 环境。

和 Nginx 的取舍

维度TraefikNginx
动态服务发现原生支持需模板或手动 reload
静态文件性能一般极强
配置可读性标签分散在容器上,需全局视角集中在一份配置文件
生态与资料较少极大
复杂 rewrite 规则不支持,需中间件或应用侧处理非常灵活

我的实践是:前面放一层 Nginx 处理静态资源和复杂 rewrite,后面用 Traefik 管容器路由。如果只有一个静态站点,别上 Traefik,纯属给自己加负担。

常见问题

Traefik 的规则为什么写反引号?

因为 YAML 里用双引号包裹字符串时,内部的 双引号 需要转义。反引号在 YAML 里表示不转义字符串,写 Host(`example.com`) 更清爽。如果你用单引号包裹整个字符串,则无需反引号。

443 端口不生效、访问超时怎么办?

先确认 entrypoints.websecure.address=:443 已配置且端口已映射,再看 Router 是否挂上了 tls.certresolver。证书未签发成功时 Traefik 不会监听 443,日志里会有 ACME 相关报错,多半是 80 端口无法从公网访问导致 httpchallenge 失败。

能不能让某个容器不暴露出去?

两件事一起做:一是 providers.docker.exposedbydefault=false,默认不暴露;二是对该容器不写 traefik.enable=true。反过来只想临时关掉某个服务,把标签改成 traefik.enable=false 即可,不用改端口。