SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

Traefik v2 升级 v3 迁移指南:配置变更与报错修复

Traefik v3 移除了 swarmMode 和 pilot 等配置,导致服务无法启动。本文详细解析 ipAllowList 迁移、HTTP/3 启用方式及弃用选项处理,助您快速修复配置错误并平滑升级至 v3 版本。

Traefik v2 和 v3 有哪些变化

从 Traefik v2 迁移到 v3 主要是重命名工作,最典型的变更是将 ipWhiteList 中间件重命名为 ipAllowList。除此之外,v3 收紧了路由规则语法(PathPrefix 不再支持正则表达式功能,部分匹配器已重命名或移除),并直接删除了部分 provider 和选项,但其他配置仍可继续使用:entrypoints、ACME 证书配置、Docker 标签工作流以及您的 acme.json 都可以沿用。v3 还提供兼容模式,可继续使用 v2 规则语法。这样您可以先升级二进制文件,再逐个服务重写规则,而不必在一个高风险的晚上一次性完成全部变更。

本指南假设您使用 Traefik 反向代理指南 中基于标签的 Docker Compose 配置。该页面采用 v3 原生配置;本指南适用于仍在运行 traefik:v2 标签的服务器。

重命名与移除项

  • ipWhiteList 现已更名为 ipAllowList,适用于 HTTP 和 TCP 中间件。内部选项保持不变,因此 sourcerange 的含义完全一致。当前的 v3 版本(包括 v3.7)仍将旧名称作为已弃用的别名处理,并继续强制执行列表,同时记录一条弃用警告。因此,此次重命名不会导致服务中断。建议尽快重命名:旧名称已被弃用,且 v2.11 已支持 ipAllowList,因此可以在升级前完成此项更改。
  • providers.docker.swarmMode=true 已移除。Swarm 现拥有独立的提供程序,配置为 providers.swarm.endpoint。
  • pilot 部分已完全移除。
  • experimental.http3 已移除。HTTP/3 现在直接在入口点(entrypoint)上启用。
  • tls.caOptional 已从提供程序和 forwardAuth 中间件中移除。如果该中间件位于 自托管 Authentik SSO 前端,删除 caOptional 行即完成了全部迁移工作,因为 forwardAuth 地址、受信任的标头以及其后的 outpost 在 v3 中的行为完全相同。
  • InfluxDB v1 指标提供程序、Rancher 提供程序以及 Marathon 提供程序均已移除。
  • 追踪功能已迁移至 OpenTelemetry。专用的追踪后端(包括 Jaeger 和 Zipkin 集成)已移除,v3 改为导出 OTLP(OpenTelemetry 协议)。
  • headers 中间件内已弃用的 ssl* 选项(sslRedirect、sslHost 及其他)已移除。入口点重定向和 redirectScheme 中间件已取代它们。

这些移除项的影响比预想中更大,因为如果静态配置中包含已移除或无法识别的选项,Traefik 将拒绝启动。残留的 pilot、swarmMode、experimental.http3 或提供程序 tls.caOptional 行会导致容器在启动时停止:Traefik 首先会记录一行指出残留项的日志(例如:Docker 提供程序 tls.CAOptional 选项已在 v3 中移除),随后以 incompatible deprecated install configuration option found 错误退出。v3.4 及之前的版本将该错误信息表述为 incompatible deprecated static option found。如果选项是 Traefik 从未识别的内容(例如拼写错误),它会以 field not found 和节点信息停止。在更改镜像标签之前,请务必清理静态配置。

如果中间件名称 Traefik 确实无法识别(拼写错误或已被移除而非重命名的名称),其表现会有所不同:引用该中间件的路由将无法加载,仪表板会标记该错误,API 会报告 middleware "offce@docker" does not exist。由于路由未成功启动,对该主机名的请求将返回 404。请注意,ipwhitelist 在当前的 v3 版本中不属于此类:它作为已弃用的别名保留了下来,因此未重命名的标签仍可正常工作。

规则语法变更

规则是实现实际重写的地方。v3 版本的变更如下:

  • 引号规则未变。两个版本均支持使用反引号或转义双引号包裹规则值,且均不支持单引号。因此,Host(app.example.com) 和转义双引号形式的 Host("app.example.com") 依然有效。
  • PathPrefix 不再支持正则表达式或 {id} 风格的占位符。v2 版本中的 PathPrefix(/api/{version:v[0-9]+}) 等规则必须改为使用 Go 正则表达式语法的 PathRegexp 匹配器。
  • 匹配器现在仅接受单个值。v2 允许 Host(app.example.com,www.example.com);v3 要求写成 Host(app.example.com) || Host(www.example.com)。例外情况是 Header、HeaderRegexp、Query 和 QueryRegexp,它们仍支持名称加值的格式。
  • Headers 和 HeadersRegexp 已重命名为 Header 和 HeaderRegexp。
  • HostHeader 已移除。请使用 Host,它在 v3 中实现相同匹配功能。
  • 新增了两个匹配器:PathRegexp 和 QueryRegexp。用于在规则内匹配客户端地址的 ClientIP 在 v2.11 中已存在,并保持不变。

好消息是:使用反引号编写的简单 Host(app.example.com) 规则在 v3 中已经是有效的语法。大多数小型 Compose 配置正是这样使用的,这意味着大多数标签无需修改规则即可迁移。

开始前审计标签

只需执行一次搜索,即可估算迁移规模,因为每个不兼容的标签变更都会留下可由 grep 查找的模式:

grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.yml

每个匹配结果对应一行需要修改的配置。ipwhitelist 改为 ipallowlist。HostHeader 改为 Host。Headers 改为 Header。{...} 中的 PathPrefix 占位符改为 PathRegexp 匹配器。Host() 中的逗号改为两个由 || 连接的 Host() 匹配器。没有匹配结果,表示标签已经符合 v3 语法,迁移工作可缩减为静态配置和镜像标签。若匹配结果充满整个屏幕,也可以借此评估该代理是否仍适合这台主机;Traefik 与 Nginx 和 Caddy 的比较 会将这部分重写成本,与另外两者要求您为每个应用完成的工作进行对比。

保持不变的部分

入口点及其 HTTP 到 HTTPS 的重定向、支持两种质询类型的 ACME 解析器、exposedByDefault、路由器和服务标签、loadbalancer.server.port 以及仪表板,在 v3 中的工作方式与 v2 相同。证书也会继续保留,因为 v3 仍会读取 v2 写入的 acme.json。不过,开始前仍应备份该文件,因为回滚时如果丢失它,就会直接触发 Let's Encrypt 的重复证书速率限制:

cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backup

迁移路径

第 1 步:锁定当前运行的版本。 将所有 traefik:latest 或 traefik:v2 标签更改为您当前使用的确切版本(例如 traefik:v2.11),并将整个 compose 目录提交到 git。后续的每一步操作都可以通过 checkout 回滚。如果您对使用 docker compose up -d <service> 重建单个服务还不熟悉,Docker Compose 基础指南 涵盖了本次迁移所依赖的操作。

第 2 步:清理静态配置并开启兼容模式。 移除 v3 版本中已废弃的所有选项(pilot、swarmMode、tls.caOptional、experimental.http3),然后告知 v3 默认将规则视为 v2 语法。在 traefik.yml 中配置:

core:
  defaultRuleSyntax: v2

或者作为 compose command: 列表中的一个标志:--core.defaultRuleSyntax=v2。兼容模式仅涵盖规则语法。它不会恢复已移除的选项,也不会为您重命名中间件。

第 3 步:在 v2.11 版本下应用中间件重命名。 在您的 compose 文件中搜索旧名称:grep -rn ipwhitelist docker-compose*.yml。将每个 ipwhitelist 标签编辑为 ipallowlist,并使用 docker compose up -d 重建这些服务。v2.11 版本已内置 IPAllowList 中间件,因此重命名后的标签在切换前即可生效,且 IPWhiteList 的弃用警告将从您的 v2 日志中消失。早于 v2.11 的版本无法识别新名称,因此如果您在第 1 步中锁定了更旧的 v2 版本,请先升级到 traefik:v2.11。(如果遗漏了一个,当前的 v3 版本仍会将旧名称作为弃用别名处理,因此列表会继续生效;请在后续工作中修复它,而不是在凌晨两点紧急处理。)

第 4 步:切换镜像标签。 将 Traefik 镜像设置为当前的 v3 版本,截至 2026 年 10 月 11 日为 traefik:v3.7(v3.7.14 是最新的补丁版本),然后执行:

docker compose up -d
docker compose logs -f traefik

由于开启了兼容模式,您的 v2 规则将继续匹配;由于中间件重命名已在 v2.11 上生效,这些路由将正常启动。健康的日志中不应包含 field not found 行和 does not exist 行。

请客观评估此步骤带来的停机窗口。如果路由引用的中间件名称是 v3 无法识别的(例如拼写错误或已移除的选项),那么从新 Traefik 启动的那一刻起,该路由就会失效,直到您修复其标签并重建应用容器为止。如果某个路由确实不能中断,请在切换前从该路由的 middlewares 标签中移除可疑的中间件,并在切换后再重新添加;请提前决定该路由在切换期间是否可以暂时失去该中间件的功能。

第 5 步:逐个服务迁移规则。 一次处理一个应用:将其规则重写为 v3 语法,仅使用 docker compose up -d app 重建该服务,并在继续下一步之前进行测试。如果某个服务包含您暂时无法重写的规则,请为该路由添加逃生舱标签 traefik.http.routers.app.ruleSyntax=v2,然后继续进行其他迁移。

第 6 步:关闭兼容模式。 当所有规则都已转换为 v3 语法后,删除 defaultRuleSyntax 以及任何 ruleSyntax 标签,重启 Traefik,并确认仪表盘中所有路由的状态均为绿色。不要长期依赖兼容模式:Traefik 已在 v3.4 中弃用了这两个选项,并将在下一个主版本中移除它们,因此它们只是过渡方案,而非最终目标。

迁移前后:一个服务的标签

下面是一个一次性包含所有典型变更的应用:多值 Host、PathPrefix 占位符,以及 ipWhiteList 中间件。v2 配置块:

  app:
    image: app:1.4
    restart: unless-stopped
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`app.example.com`,`www.example.com`) && PathPrefix(`/api/{version:v[0-9]+}`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.routers.app.middlewares=office
      - traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24
      - traefik.http.services.app.loadbalancer.server.port=8080

同一服务迁移到 v3 后:

  app:
    image: app:1.4
    restart: unless-stopped
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=(Host(`app.example.com`) || Host(`www.example.com`)) && PathRegexp(`^/api/v[0-9]+`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.routers.app.middlewares=office
      - traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.0/24
      - traefik.http.services.app.loadbalancer.server.port=8080

有两个标签发生了变化。规则将多值 Host 拆分为两个由 || 连接的匹配器,并将占位符替换为 PathRegexp;中间件标签则将 ipwhitelist 替换为 ipallowlist。入口点、证书解析器、路由器到中间件的关联关系,以及服务端口均未改变。

使用控制面板测试每项服务

每次切换后,打开控制面板的 HTTP 路由页面。所有路由都应显示为绿色。带有错误标记的路由会指出具体问题。通常是中间件在更名后不存在,或规则 v3 无法解析。然后从外部逐个主机名确认:

curl -sI https://app.example.com/api/v1/status

出现 200 或应用的正常重定向,表示路由和 TLS 均正常。Traefik 返回 404,表示路由未启动;返回控制面板并查看错误信息。操作期间,在第二个终端中保持 docker compose logs -f traefik 打开,因为每次容器重启时,所有解析失败都会立即记录在那里。

回滚的完整性

保留 v2 版本的 compose 文件、其静态配置以及 acme.json 备份,直到所有服务均已在 v3 版本上完成路由配置并经过实际验证。回滚意味着检出迁移前的提交并运行 docker compose up -d。回滚必须针对整个文件,而不仅仅是镜像标签,因为 v3 专有的语法在 v2 下会报错,正如 v2 语法在 v3 下不兼容一样:PathRegexp 匹配器无法在 v2 中解析。重命名后的 ipallowlist 标签在 v2.11 版本中可用,但在任何更早的 v2 版本中均无法识别。如果 acme.json 在过程中丢失或损坏,请在启动 v2 之前恢复备份副本,以避免回滚时因同时重新签发 5 个证书而耗尽 Let's Encrypt 的速率限制。

FAQ

我需要重写 Traefik v3 的所有路由规则吗?

不需要。使用反引号编写的普通 Host(app.example.com) 规则在两个版本中均有效,这涵盖了大多数 Compose 配置。仅当规则使用了 v2 独有功能时才需要重写:例如 Path 和 PathPrefix 内部的正则表达式或占位符、单个 Host() 内包含多个主机名,或者已移除的 Headers、HeadersRegexp 和 HostHeader 匹配器。

Traefik v3 中的 ipWhiteList 发生了什么变化?

它被重命名为 ipAllowList,内部配置保持不变,因此 v2 标签如 traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 只需将名称替换为 ipallowlist 即可。v2.11 已经支持新名称,因此您可以在升级前进行重命名。当前的 v3 版本(包括 v3.7)仍将旧名称作为弃用别名处理,因此未重命名的标签仍会强制执行白名单,仅会在日志中产生警告。请将其视为过渡期而非跳过重命名的理由:弃用的名称随时可能在后续版本中移除,而如果 Traefik 确实无法识别中间件名称,则会报错并导致路由失效,返回 404。仪表板会显示该错误,且对该主机名的请求将返回 404。

Traefik v3 还能读取 v2 规则语法吗?

可以。在静态配置中设置 core.defaultRuleSyntax: v2 可在迁移期间保持 v2 语法作为默认值,并在切换回默认值后,针对个别滞后的路由使用 ruleSyntax=v2 标签。请将两者视为临时方案:Traefik 已在 v3.4 中弃用它们,并将在下一个大版本中移除。

我的 Let's Encrypt 证书在升级后还能用吗?

可以。Traefik v3 会继续读取 v2 生成的 acme.json 文件,因此证书不会仅仅因为二进制文件变更而重新签发。无论如何,请在开始前将该文件备份到安全位置,因为回滚或删除卷导致 acme.json 丢失会强制所有证书同时重新签发,而 Let's Encrypt 对同一组主机名每周仅允许签发 5 次重复证书。

为什么 Traefik v3 在升级后无法启动?

通常是因为静态配置中仍包含 v3 已移除的选项,Traefik 会拒绝识别并启动。对于已知的残留项(pilot、providers.docker.swarmMode、experimental.http3 以及提供程序的 tls.caOptional),日志会指出具体条目并提示 incompatible deprecated install configuration option found(在 v3.4 及更早版本中为 incompatible deprecated static option found);对于 v3 从未识别的内容(如拼写错误),日志会提示 field not found 并指出节点位置。删除或替换这些条目,然后重新启动容器即可。