首页
/ Traefik 仪表盘自定义路径暴露:多 Provider 完整配置与 api@internal 源码原理

Traefik 仪表盘自定义路径暴露:多 Provider 完整配置与 api@internal 源码原理

2026-09-04 17:53:37作者:裘晴惠Vivianne

本文围绕 Traefik 仓库中的官方示例片段 include-dashboard-custom-path-examples.md 展开,讲解如何把 Traefik 内置的 API 与 Dashboard 从默认路径(/api/dashboard)迁移到一个自定义路径前缀(示例中使用 /traefik),并叠加 Basic Auth 认证;覆盖 Docker、Docker Swarm、Kubernetes CRD、Consul Catalog、File(YAML/TOML)六种 Provider 的完整可复制配置,并结合 internal provider 源码Basic Auth 中间件源码 剖析 api@internal 这一内置服务的真实作用与认证校验流程。读完本文,你可以独立完成仪表盘路径改造、理解自定义 Router 与内部 Router 的优先级关系,并掌握 apr1 哈希用户文件的生成与转义规则。

一、背景:Traefik 内置 API/Dashboard 的默认路由

在自定义之前,先弄清楚 Traefik 默认把 Dashboard 放在哪里。internal provider 会在启动时根据静态配置自动注入一组内置 Router。从 apiConfiguration 实现 可以看到:

  • 当且仅当静态配置中 api.insecure = true 时,才会创建默认路由:
    • api Router:规则 PathPrefix(\/api`),服务 api@internal,优先级 math.MaxInt - 1`;
    • dashboard Router(当 api.dashboard = true 时):规则 PathPrefix(\/`),服务 dashboard@internal,优先级 math.MaxInt - 2,并挂上两个内部中间件 dashboard_redirect@internal(把根路径 301 重定向到 /dashboard/)与 dashboard_stripprefix@internal(剥离 /dashboard/` 前缀);
    • debug Router(当 api.debug = true 时):规则 PathPrefix(\/debug`)`。
  • 这些默认路由都绑定在名为 traefik 的默认入口点上。

也就是说,默认情况下 Dashboard 位于 traefik 入口点下的 /(经重定向落到 /dashboard/),JSON API 位于 /api。当你希望把整个 Dashboard 收拢到 https://traefik.example.com/traefik 这样一条独立路径下——例如避免与后端业务路径冲突、或配合统一网关的路径规划——就需要用一条自己的 Router 重新指到内部服务 api@internal 上。这正是官方示例片段要解决的问题。

二、核心思路:一条规则 + api@internal + auth 中间件

官方示例给出的自定义路径配置,其结构在六个 Provider 中完全一致,核心要素只有三个:

  1. 路由规则Host(\traefik.example.com`) && PathPrefix(`/traefik`)——按域名 + 自定义前缀匹配,取代默认的 PathPrefix(`/api`) || PathPrefix(`/dashboard`)`;
  2. 服务api@internal——直接复用 internal provider 注入的内置服务,不经过后端转发,@internal 后缀表示这是跨 Provider 引用的内部服务(Kubernetes Gateway API 路径下同样支持该引用,参见 httproute.go 中的注释);
  3. 认证中间件auth(Basic Auth),用户以 用户名:apr1 哈希 形式配置。

请求处理链在 internalhandler.go 中收口:服务名 api@internal 会被分发到内部 API handler,返回 Traefik 自身的 JSON API 与嵌入式 Web 控制台前端。

三、六种 Provider 的完整配置示例

以下示例完整继承自 include-dashboard-custom-path-examples.md,可直接复制使用(traefik.example.com 与用户哈希请替换为实际值)。

3.1 Docker(普通容器,labels 方式)

# Dynamic Configuration
labels:
  - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)"
  - "traefik.http.routers.dashboard.service=api@internal"
  - "traefik.http.routers.dashboard.middlewares=auth"
  - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"

3.2 Docker Swarm(deploy.labels 方式)

# Dynamic Configuration
deploy:
  labels:
    - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)"
    - "traefik.http.routers.dashboard.service=api@internal"
    - "traefik.http.routers.dashboard.middlewares=auth"
    - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
    # Dummy service for Swarm port detection. The port can be any valid integer value.
    - "traefik.http.services.dummy-svc.loadbalancer.server.port=9999"

Swarm 模式下多出的 dummy-svc 是官方注释中说明的"端口探测占位服务":Swarm 依靠容器发布的端口做服务发现,加一个任意合法端口的假服务可以让 provider 正确识别该任务。

3.3 Kubernetes(IngressRoute + Middleware CRD)

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
spec:
  routes:
  - match: Host(`traefik.example.com`) && PathPrefix(`/traefik`)
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
    middlewares:
      - name: auth
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: auth
spec:
  basicAuth:
    secret: secretName # Kubernetes secret named "secretName"

Kubernetes 与其他 Provider 的显著差异:用户名哈希不直接写在 Middleware 里,而是引用名为 secretName 的 Kubernetes Secret(secret 字段),把凭据从 CRD 中隔离出来。

3.4 Consul Catalog(key-value 标签方式)

# Dynamic Configuration
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"

3.5 File Provider(YAML 动态配置)

# Dynamic Configuration
http:
  routers:
    dashboard:
      rule: Host(`traefik.example.com`) && PathPrefix(`/traefik`)
      service: api@internal
      middlewares:
        - auth
  middlewares:
    auth:
      basicAuth:
        users:
          - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
          - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"

3.6 File Provider(TOML 动态配置)

# Dynamic Configuration
[http.routers.my-api]
  rule = "Host(`traefik.example.com`) && PathPrefix(`/traefik`)"
  service = "api@internal"
  middlewares = ["auth"]

[http.middlewares.auth.basicAuth]
  users = [
    "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
    "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
  ]

注意 Docker/Consul 的 label 值里写的是 $$apr1$$,而 File 配置里是单 $。这是 Docker 对 $ 的转义约定:$$ 在解析后得到字面量 $,最终传给 Traefik 的都是 test:$apr1$H6uskkkW$... 这一形式的 apr1 哈希。

四、源码级原理佐证

4.1 为什么自定义 Router 能接管 Dashboard

api@internal 服务由 internal provider 无条件注册:internal.gocfg.HTTP.Services["api"] = &dynamic.Service{}api 非 nil 时总是执行(无论 insecure 与否)。而默认的两条 Router(apidashboard)仅在 api.insecure = true 时创建,且优先级分别被设为 MaxInt - 1MaxInt - 2。你自定义的 dashboard Router 未显式指定 priority,从源码结构看,其优先级由规则复杂度计算得出;若出现与默认路由的匹配重叠,可在自己的 Router 上显式声明更大的 priority 来确保自定义路径优先生效。

4.2 Basic Auth 的校验实现

auth 中间件的实现位于 basic_auth.go

  • 通过 getUsers 解析 users 列表(或 usersFile 文件),要求至少存在一个用户,否则中间件创建直接报错;
  • 采用 goauth.CheckSecret 做常量时间的哈希比对,且当用户不存在时仍会用首个哈希做一次"影子计算"(notFoundSecret),源码注释说明这是为了防止时序攻击(timing attack);
  • 请求经 req.BasicAuth() 提取用户名/口令后进入比对流程,失败则返回 401 并触发 WWW-Authenticate 头(Realm 可配置,默认值见 defaultRealm 常量)。

示例中的 $apr1$H6uskkkW$... 是 Apache MD5-Crypt(htpasswd 的 apr1 算法)格式哈希:$apr1$ 标记算法、H6uskkkW 为 8 字符盐、其余为哈希体,可用 htpasswd -nb -B 用户名 口令 离线生成后填入配置,无需在 Traefik 中保存明文口令。

五、验证与注意事项

  1. 验证路由生效:改造完成后,可通过内部 API 查看动态路由,确认 dashboard 规则与 auth 中间件已挂载:GET http://<traefik-host>/api/http/routers/dashboard(API 需先关闭 insecure 或本身暴露时才可达,此时可经自定义路径 /traefik/api 间接访问);
  2. 默认路径与自定义路径的关系:本示例只新增/覆盖一条 Router,不会删除默认的 api/dashboard 路由。若希望仅保留自定义路径这一入口,从源码行为看,可将静态配置的 api.insecure 置为 false 以抑制内部注入的默认 Router(apiConfiguration 中的默认路由创建分支依赖该开关),仅保留自定义路由引用 api@internal 的路径;
  3. 与默认示例的差异:仓库中另一份官方示例 include-dashboard-examples.md 使用的规则是 PathPrefix(\/api`) || PathPrefix(`/dashboard`),即保持默认双路径;本文对应的 custom-path 示例将其收敛为单一前缀 PathPrefix(`/traefik`)`,这是两者唯一的规则差异,认证与服务的接法完全一致;
  4. TOML 示例的 Router 命名:File (TOML) 示例中 Router 名为 my-api,其余 Provider 示例中为 dashboard,二者无功能差别,命名可自定,但建议与语义(dashboard)保持一致以便排障时检索。

相关仓库路径internal provider 默认路由注入内部服务分发Basic Auth 中间件Gateway API 对 api@internal 的引用支持静态配置示例

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384