Traefik — API Surface#
API types#
Traefik exposes five distinct API surfaces:
- REST/HTTP management API — read-only introspection of live routing state
- CLI — startup, healthcheck, and version commands
- Middleware system — extensive built-in HTTP and TCP middleware catalog
- Plugin / Extension system — Yaegi (interpreted Go) and WASM plugins for middleware and providers
- Dynamic configuration interface — provider-based config (Docker labels, K8s CRDs, files, HTTP polling) — the primary operational surface
REST/HTTP API#
- Router:
github.com/gorilla/mux(pkg/api/handler.go:86) - Route registration: All routes registered manually in
Handler.createRouter()at startup. No annotations, no code generation. Routes are hard-coded. - Middleware chain: None explicitly set on the API router; the API is served as a standard Traefik route through the regular pipeline (auth, IP allow-listing, etc. can be layered via dynamic config). The internal provider creates the API router and services.
- Authentication: Not built into the API handler itself. Users secure the API by attaching auth middlewares (BasicAuth, ForwardAuth, IPAllowList) via dynamic config on the router pointing to the API service.
- Base path: Configurable via
static.Configuration.API.BasePath(defaults to empty — routes live at/api/...).
Key endpoints#
| Method | Path | Handler | Description |
|---|---|---|---|
| GET | /api/rawdata | getRuntimeConfiguration | Full runtime config dump — all routers, services, middlewares for HTTP/TCP/UDP |
| GET | /api/overview | getOverview | Summary counts (experimental) |
| GET | /api/support-dump | getSupportDump | Support bundle for debugging |
| GET | /api/entrypoints | getEntryPoints | List all entrypoints |
| GET | /api/entrypoints/{entryPointID} | getEntryPoint | Single entrypoint detail |
| GET | /api/http/routers | getRouters | List HTTP routers |
| GET | /api/http/routers/{routerID} | getRouter | Single HTTP router |
| GET | /api/http/services | getServices | List HTTP services |
| GET | /api/http/services/{serviceID} | getService | Single HTTP service |
| GET | /api/http/middlewares | getMiddlewares | List HTTP middlewares |
| GET | /api/http/middlewares/{middlewareID} | getMiddleware | Single HTTP middleware |
| GET | /api/tcp/routers | getTCPRouters | List TCP routers |
| GET | /api/tcp/routers/{routerID} | getTCPRouter | Single TCP router |
| GET | /api/tcp/services | getTCPServices | List TCP services |
| GET | /api/tcp/services/{serviceID} | getTCPService | Single TCP service |
| GET | /api/tcp/middlewares | getTCPMiddlewares | List TCP middlewares |
| GET | /api/tcp/middlewares/{middlewareID} | getTCPMiddleware | Single TCP middleware |
| GET | /api/udp/routers | getUDPRouters | List UDP routers |
| GET | /api/udp/routers/{routerID} | getUDPRouter | Single UDP router |
| GET | /api/udp/services | getUDPServices | List UDP services |
| GET | /api/udp/services/{serviceID} | getUDPService | Single UDP service |
| GET | /api/version | version.Handler.Append | Traefik version info |
Debug endpoints (when api.debug = true)#
Registered via DebugHandler.Append() (pkg/api/debug.go):
| Method | Path | Description |
|---|---|---|
| GET | /debug/vars | Go expvar metrics (goroutine count, etc.) |
| GET | /debug/pprof/ | pprof index |
| GET | /debug/pprof/cmdline | pprof cmdline |
| GET | /debug/pprof/profile | pprof CPU profile |
| GET | /debug/pprof/symbol | pprof symbol lookup |
| GET | /debug/pprof/trace | pprof trace |
Ping endpoint#
Registered separately from the main API, handled by pkg/ping/ping.Handler which implements http.Handler:
- Path:
/ping(on a configurable entrypoint, default:traefik) - Method: Any (responds to HEAD and GET)
- Responses:
200 OKduring normal operation; configurable non-200 status (TerminatingStatusCode) during graceful shutdown
Design note: The API is entirely read-only (all GET). There are no write endpoints — configuration is changed exclusively through providers. This is a deliberate design choice: the API is for observability, not control. The dashboard (pkg/api/dashboard/dashboard.go) is served from the same router using gorilla/mux.Router.PathPrefix to serve embedded web assets.
gRPC API#
Not present. The only .proto file in the repository (integration/helloworld/helloworld.proto) is an integration test fixture used to test gRPC-proxying capabilities — Traefik proxies gRPC traffic but does not expose a gRPC management API.
CLI#
- Framework: Custom —
github.com/traefik/paerser/cli(Traefik’s own CLI library, extracted from the main repo) - Command structure:
traefik # Main binary — starts the proxy
healthcheck # Checks liveness via the ping endpoint
version # Prints version infoCommand definition: Each command is a
*cli.Commandstruct withName,Description,Configuration(the typed config struct), and aRunfunction. Subcommands added viaAddCommand().Flag patterns:
- Configuration struct fields are auto-exposed as flags via
paerser’s reflection-based flag encoder (flag.Encode/flag.Decode) - Struct tags (
description,json,toml,yaml,export) drive both documentation and serialization - Environment variable binding:
TRAEFIK_<UPPERCASE_FLAG_PATH>— handled byEnvLoader - Config file (YAML/TOML): handled by
FileLoader - Deprecation warnings for renamed flags: handled by
DeprecationLoader - Loader precedence:
DeprecationLoader → FileLoader → FlagLoader → EnvLoader - No global persistent flags — the config struct is passed through to all loaders
- Configuration struct fields are auto-exposed as flags via
Middleware system (built-in)#
Traefik’s middleware catalog is the richest part of its operational API surface. All middlewares are referenced by name in dynamic config and constructed by pkg/server/middleware.Builder.BuildMiddlewareChain() using containous/alice for composition.
HTTP middlewares (pkg/middlewares/)#
| Middleware | Package | Description |
|---|---|---|
| AddPrefix | addprefix | Prepends a path prefix before forwarding |
| BasicAuth | auth | HTTP Basic authentication |
| DigestAuth | auth | HTTP Digest authentication |
| ForwardAuth | auth | Delegates auth to an external service |
| Buffering | buffering | Buffers request/response bodies |
| Chain | chain | Groups multiple middleware into a named chain |
| CircuitBreaker | circuitbreaker | Opens circuit on error thresholds; uses gobreaker |
| Compress | compress | Response compression (gzip, brotli, zstd) |
| ContentType | contenttype | Auto-detects Content-Type on responses |
| EncodedCharacters | encodedcharacters | Handles encoded characters in paths |
| CustomErrors | customerrors | Returns custom error pages for configured status codes |
| GrpcWeb | grpcweb | Translates gRPC-Web to gRPC for browser clients |
| Headers | headers | Add/modify/remove request and response headers |
| IPAllowList | ipallowlist | Restricts access by client IP |
| IPWhiteList | ipwhitelist | Deprecated alias for IPAllowList |
| InFlightReq | inflightreq | Limits concurrent in-flight requests |
| PassTLSClientCert | passtlsclientcert | Passes client TLS cert info as request header |
| RateLimiter | ratelimiter | Token-bucket rate limiting per client |
| RedirectScheme | redirect | Forces HTTPS redirect |
| RedirectRegex | redirect | Regex-based URL redirect |
| ReplacePath | replacepath | Replaces the request path |
| ReplacePathRegex | replacepathregex | Regex-based path replacement |
| Retry | retry | Retries failed requests (up to N attempts) |
| StripPrefix | stripprefix | Strips a path prefix before forwarding |
| StripPrefixRegex | stripprefixregex | Regex-based prefix stripping |
| GatewayAPI: HeaderModifier | gatewayapi/headermodifier | Gateway API header manipulation |
| GatewayAPI: Redirect | gatewayapi/redirect | Gateway API redirect filter |
| GatewayAPI: URLRewrite | gatewayapi/urlrewrite | Gateway API URL rewrite filter |
| IngressNginx: RewriteTarget | ingressnginx/rewritetarget | Nginx-compat rewrite-target annotation |
| IngressNginx: AuthTLSPass | ingressnginx/authtlspasscertificatetoupstream | Nginx-compat TLS cert passthrough |
| IngressNginx: Snippet | ingressnginx/snippet | Nginx-compat nginx.ingress.kubernetes.io/configuration-snippet |
TCP middlewares (pkg/middlewares/tcp/)#
| Middleware | Package | Description |
|---|---|---|
| InFlightConn | inflightconn | Limits concurrent TCP connections |
| IPAllowList | ipallowlist | Restricts TCP access by IP |
| IPWhiteList | ipwhitelist | Deprecated alias for IPAllowList |
Middleware composition#
Middleware chains are built via alice.Chain from github.com/containous/alice. Each middleware wraps http.Handler using the standard func(http.Handler) http.Handler constructor signature. Multi-type middleware configs are rejected at build time — each middleware name maps to exactly one type.
Plugin / Extension system#
This is the primary extensibility surface for third-party code.
Mechanism: Two runtimes, unified behind the same plugin descriptor format:
- Yaegi (
github.com/traefik/yaegi): Go source code interpreted at runtime. No compilation required, version-independent. For both middleware and provider plugins. - WASM (
github.com/tetratelabs/wazero): WebAssembly modules. Language-agnostic (any language that compiles to WASM). For middleware plugins only.
- Yaegi (
Plugin types:
middleware— wraps HTTP handlers; implements the standardfunc(http.Handler) http.Handlersignature at the yaegi/WASM boundaryprovider— emits dynamic config; implements theProviderinterface (via yaegi only)
Plugin manifest: Each plugin ships a
.traefik.ymlmanifest declaring:type(middleware|provider)runtime(yaegi|wasm)import(Go package path, for yaegi)wasmPath(path to.wasmbinary, for WASM)displayName,summary,testData(required for catalog submission)
Plugin sources:
- Remote: Downloaded from the Traefik plugin catalog (
plugins.traefik.io) viapkg/plugins.Manager.InstallPlugin(). Pinned by module name + version + optional hash. Archives stored locally between restarts. - Local: Placed in
./plugins-local/<module-name>/. No version pinning.
- Remote: Downloaded from the Traefik plugin catalog (
Static config registration:
experimental: plugins: my-plugin: moduleName: github.com/example/my-traefik-plugin version: v0.1.0Builder wiring:
pkg/plugins.Builderis created at startup bycreatePluginBuilder()insetupServer(). It is passed to bothmiddleware.NewBuilder()(for plugin middlewares) andaggregator.NewProviderAggregator()(for plugin providers), behind themiddleware.PluginsBuilderinterface.Extension points: Third-party code can hook in at:
- Middleware position in any router’s middleware chain (via plugin middleware)
- Provider position in the provider aggregator (via plugin provider, emitting
dynamic.Messagejust like a built-in provider)
WASM sandbox: WASM plugins run in a wazero sandbox. The
Settingsstruct allows opt-in exposure of environment variables (Envs), host directory mounts (Mounts), and unsafe syscall access (UseUnsafe).
Dynamic configuration interface (provider-based)#
While not an API in the traditional REST/gRPC sense, the provider interface is Traefik’s primary operational control plane — how operators tell it what to route and how.
| Provider | Mechanism | How users define config |
|---|---|---|
| Docker | Docker Events API (push) | Container labels (traefik.http.routers.*, etc.) |
| Kubernetes Ingress | K8s watch | kubernetes.io/ingress.class annotation + standard Ingress spec |
| Kubernetes CRDs | K8s watch | IngressRoute, IngressRouteTCP, IngressRouteUDP, Middleware, TLSOption, etc. |
| Kubernetes Gateway API | K8s watch | Gateway, HTTPRoute, TCPRoute, GRPCRoute, etc. |
| Consul | Consul watch | KV entries |
| etcd | etcd watch | KV entries |
| File | inotify / polling | YAML or TOML config files (supports directory: for multi-file) |
| HTTP | HTTP polling | JSON/TOML/YAML served by a remote URL |
| ECS | AWS API polling | ECS task labels |
| Nomad | Nomad API watch | Nomad service tags |
| Tailscale | Tailscale API | Automatic cert resolver per Tailscale host |
| Internal | Built-in (no user config) | Wires /api, /ping, /dashboard routes |
All providers implement the same two-method interface:
type Provider interface {
Init() error
Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error
}Config keys follow a consistent naming scheme: traefik.http.routers.<name>.rule, traefik.http.services.<name>.loadbalancer.server.port, etc. The same DSL works uniformly across Docker labels, K8s annotations, and file config — the config struct (pkg/config/dynamic) is the canonical schema.