项目:traefik/traefik | 星数:65409 | 语言:Go | 协议:MIT | GitHub仓库
更新日期:2026-10-30 · 作者:CodeArts 编辑部
我最早的反向代理是 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 吃掉了。
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,会让所有容器自动暴露到公网,包括你没打算公开的数据库和管理面板。
挂 /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 路线。
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 环境。
| 维度 | Traefik | Nginx |
|---|---|---|
| 动态服务发现 | 原生支持 | 需模板或手动 reload |
| 静态文件性能 | 一般 | 极强 |
| 配置可读性 | 标签分散在容器上,需全局视角 | 集中在一份配置文件 |
| 生态与资料 | 较少 | 极大 |
| 复杂 rewrite 规则 | 不支持,需中间件或应用侧处理 | 非常灵活 |
我的实践是:前面放一层 Nginx 处理静态资源和复杂 rewrite,后面用 Traefik 管容器路由。如果只有一个静态站点,别上 Traefik,纯属给自己加负担。
因为 YAML 里用双引号包裹字符串时,内部的 双引号 需要转义。反引号在 YAML 里表示不转义字符串,写 Host(`example.com`) 更清爽。如果你用单引号包裹整个字符串,则无需反引号。
先确认 entrypoints.websecure.address=:443 已配置且端口已映射,再看 Router 是否挂上了 tls.certresolver。证书未签发成功时 Traefik 不会监听 443,日志里会有 ACME 相关报错,多半是 80 端口无法从公网访问导致 httpchallenge 失败。
两件事一起做:一是 providers.docker.exposedbydefault=false,默认不暴露;二是对该容器不写 traefik.enable=true。反过来只想临时关掉某个服务,把标签改成 traefik.enable=false 即可,不用改端口。