Skip to content

Traefik 入门常见问题(FAQ) ​

为什么 Traefik 返回某个特定的 HTTP 响应码? ​

Traefik 是一个动态反向代理 —— 虽然文档中经常通过文件配置示例来演示配置选项,但 Traefik 的核心特性是它的动态可配置性,能够随着时间直接响应来自 Provider 的变化。

具体来说,安装配置 是静态的,可以由启动时的文件提供,而像文件 Provider 这样的多种 Provider 则在 Traefik 实例的整个生命周期内持续为 路由配置 的变化做出动态贡献。

此外,配置还包含一些概念,例如入口点(EntryPoint) —— 可以将其视为传输层(TCP)上的一个监听器;而路由器(Router) 则更偏向表示层(TLS)和应用层(HTTP)。对于给定的入口点,可以存在任意数量的路由器。

换句话说,对于一个给定的入口点,任意时刻观察到的流量不一定只与一种协议相关。可能是 HTTP,也可能是其他;可能使用 TLS,也可能没有。更不用说动态配置的改变可能会让这种流量随时间变化。

因此,在这种动态上下文中,entryPoint 的静态配置并不能提供任何关于通过该 entryPoint 的流量将如何路由的线索。也不能确定它是否会被路由 —— 也就是说,是否存在与通过该入口点的流量类型相匹配的路由器。

404 Not Found(未找到) ​

Traefik 在以下情况下返回 404 响应码:

  • 请求到达的入口点没有路由器
  • 请求到达的入口点没有 HTTP 路由器(且请求是 HTTP)
  • 请求到达的入口点没有 HTTPS 路由器(且请求是 HTTPS)
  • 请求到达的入口点上有 HTTP/HTTPS 路由器,但没有任何匹配上

从 Traefik 的角度来看,每次请求无法与路由器匹配时,正确的响应码就是 404 Not Found。

在这种情况下,响应码不是 503 Service Unavailable,因为 Traefik 无法确认"缺少匹配的路由器"只是暂时性的。Traefik 的路由配置是动态的、并从不同的 Provider 聚合而来,因此它无法在任意时刻假定某个特定路由"应该"被处理或"不应该"被处理。

此行为与 RFC 7231 一致:

服务器当前由于临时过载或维护而无法处理该请求。含义是:这是一个临时状态,在经过一定延迟后会缓解。如果已知延迟时长,可以在 Retry-After 响应头中给出。如果未给出 Retry-After,客户端应按照 500 响应的方式处理。

注意:503 状态码的存在并不意味着服务器在过载时必须使用它 —— 一些服务器可能选择直接拒绝连接。

—— 摘自 rfc7231#section-6.6.4

502 Bad Gateway(网关错误) ​

当联系上游服务时发生错误,Traefik 返回 502 响应码。

503 Service Unavailable(服务不可用) ​

当请求匹配了某个路由器,但没有就绪的服务器可以处理该请求时,Traefik 返回 503 响应码。

这种情况出现在:服务被显式配置为不包含任何服务器;或者服务启用了健康检查,且所有服务器都不健康时。

不使用 404 而使用其他状态码 ​

有时 404 响应码与其它组件或服务(如 CDN)配合得并不好。

在这些情况下,你可能希望 Traefik 始终回复 503 响应码,而不是 404。

要实现这种行为,可以创建一个 catchall(兜底)路由器 —— 使用最低的优先级并路由到一个没有服务器的服务 —— 这样当没有任何其它路由器匹配时,它就会处理所有请求。

下面是一个仅使用文件 Provider 的 yaml 示例,展示了这种配置可能的样子:

静态配置:

yaml
# traefik.yml
entryPoints:
  web:
    address: :80

providers:
  file:
    filename: dynamic.yaml

动态配置:

yaml
# dynamic.yaml
http:
  routers:
    catchall:
      # 仅绑定到 web 入口点
      entryPoints:
        - "web"
      # 兜底规则
      rule: "PathPrefix(`/`)"
      service: unavailable
      # 最低的优先级
      # 在没有其它路由器匹配时才会被评估
      priority: 1

  services:
    # 该服务将始终返回 503 Service Unavailable
    unavailable:
      loadBalancer:
        servers: {}

专用服务

如果你需要返回除 503 之外的状态码,或返回自定义消息,可以沿用上面示例的原则(catchall 路由器),但 unavailable 服务应根据需要进行调整。


为什么 TLS 证书的内容更新时不会重新加载? ​

使用 文件 Provider 时,只有被监听(watch)的配置文件发生修改时,才会触发配置更新。

这就是为什么:当证书以路径方式定义时,即使该证书的实际内容发生了变化,也不会触发配置更新。

要使新的证书内容生效,必须强制更新动态配置。一种可行的方法是:触发文件通知事件 —— 例如在配置文件上使用 touch 命令。


代理 HTTP 请求时会添加哪些转发的头? ​

默认情况下,代理请求时会自动添加以下头:

属性HTTP 头
客户端 IPX-Forwarded-For, X-Real-Ip
主机X-Forwarded-Host
端口X-Forwarded-Port
协议X-Forwarded-Proto
代理服务器的主机名X-Forwarded-Server

更多详情,请参阅 Forwarded Header 文档。


Traefik 是如何存储和提供 TLS 证书的? ​

存储 TLS 证书 ​

TLS 证书既可以由 路由配置 直接提供,也可以由 证书解析器(Certificate resolvers) 提供。

对于每个 TLS 证书,Traefik 会生成一个标识符(identifier),作为存储它的键。该标识符是按字母顺序连接证书的 DNSNames 和 IPAddresses(SAN)得到的。

示例:

X509v3 Subject Alternative NameTLS 证书标识符
DNS:example.com, IP Address:127.0.0.1127.0.0.1,example.com
DNS:example.com, DNS:*.example.com*.example.com,example.com

该标识符用于存储 TLS 证书,以便之后用于处理 TLS 连接。每次配置发生变化时都会执行此操作。

如果多个 TLS 证书提供了相同的 SAN 定义(即相同的标识符),则只保留最先被处理的那一个。由于动态配置是从所有 Provider 聚合而来,在处理时无法保证它们的处理顺序。这意味着 —— 随着应用的配置变化 —— 给定标识符所保留的 TLS 证书也可能不同。

提供 TLS 证书 ​

对于每个传入连接,Traefik 都会为提供的服务器名提供"最佳"匹配的 TLS 证书。

TLS 证书的选择过程会先缩小与服务器名匹配的证书列表,然后按标识符字母顺序排序,最后选择该排序列表中的最后一个证书。

示例:

选中的 TLS 证书标识符排序后的 TLS 证书标识符提供的证书标识符
127.0.0.1,example.com,*.example.com,example.com*.example.com,example.com,127.0.0.1,example.com127.0.0.1,example.com
*.example.com,example.com,example.com*.example.com,example.com,example.comexample.com

缓存 TLS 证书 ​

虽然 Traefik 会为每个传入连接提供"最佳"匹配的 TLS 证书,但通过缓存机制避免了对每个传入连接都执行选择过程的开销。

一旦某个 TLS 证书被选定为服务器名的"最佳"证书,它就会被缓存 1 小时,从而避免后续连接再次执行选择过程。

不过,当应用新配置时,缓存会被重置。


"field not found" 错误是什么意思? ​

error: field not found, node: -badField-

当动态或静态配置中出现了未知属性时,就会发生 "field not found" 错误。

要检查配置文件是否格式正确,可以采用以下方法进行验证:


为什么某些资源(router、middleware、service...)未被创建/应用? ​

作为一个通用提示:如果在评估动态配置后,某个资源被 Traefik 丢弃/未创建,你应该首先查看日志中是否有错误。

如果发现错误,则该错误可以确认在创建资源时出现了问题,错误消息应能帮助你弄清楚配置中的错误并修复它。

使用文件 Provider 时,验证动态配置格式是否正确的一种方式是使用 动态配置的 JSON Schema。


为什么 Let's Encrypt 通配符证书的 DNS challenge 更新/生成会失败? ​

如果你尝试使用 DNS challenge 更新通配符证书,并出现如下错误:

msg="Error renewing certificate from LE: {example.com [*.example.com]}"
providerName=letsencrypt.acme error="error: one or more domains had a problem:
[example.com] acme: error presenting token: gandiv5: unexpected authZone example.com. for fqdn example.com."

那么问题可能与 CNAME 支持有关。

在这种情况下,请确保你的基础设施已正确设置为不依赖 CNAME 的 DNS challenge,并尝试通过以下环境变量禁用 CNAME 支持:

LEGO_DISABLE_CNAME_SUPPORT=true

在生产环境使用 Traefik OSS?

如果你在工作中使用 Traefik,可以考虑为其添加企业级 API 网关能力或获取 Traefik OSS 的商业支持。

基于 MIT 协议发布