Open-Source Wikis

/

Traefik

/

Systems

/

Configuration

traefik/traefik

Configuration

Configuration in Traefik is split into three packages. Knowing which package owns which type saves a lot of confusion when reading the source.

Three configuration kinds

Kind Package Lifecycle Sources
Static pkg/config/static Loaded at startup, immutable thereafter File (traefik.yml/.toml), CLI flags, env vars
Dynamic pkg/config/dynamic Continuously refreshed at runtime Providers (Docker, Kubernetes, file, KV stores, …)
Runtime pkg/config/runtime In-memory mirror of dynamic + status Built by pkg/server/router from dynamic

Static configuration

pkg/config/static/static_config.go defines the top-level Configuration struct. Notable fields:

Field Type Purpose
Global *Global checkNewVersion, sendAnonymousUsage.
EntryPoints EntryPoints Map of named listeners (web, websecure, traefik, …). See pkg/config/static/entrypoints.go.
Providers *Providers Per-provider configuration blobs.
API *API Dashboard / API enable + insecure / debug flags.
Metrics *otypes.Metrics Prometheus / OTLP / Datadog / StatsD / InfluxDB exporter config.
Tracing *Tracing OpenTelemetry tracer setup.
Log, AccessLog *otypes.TraefikLog, *otypes.AccessLog Logging output, level, format.
CertificatesResolvers map[string]CertificateResolver ACME / Tailscale resolvers.
Experimental *Experimental Plugins, hub, kubernetes-gateway flags.
OCSP *tls.OCSPConfig OCSP stapling.
Spiffe *SpiffeClientConfig SPIFFE workload-identity.

The static configuration also encodes the providers' precedence list:

var providerNames = []string{
    gateway.ProviderName,
    crd.ProviderName,
    ingress.ProviderName,
    ingressnginx.ProviderName,
    docker.SwarmName,
    docker.DockerName,
    file.ProviderName,
    redis.ProviderName,
    knative.ProviderName,
    consul.ProviderName,
    consulcatalog.ProviderName,
    nomad.ProviderName,
    etcd.ProviderName,
    ecs.ProviderName,
    http.ProviderName,
    zk.ProviderName,
    rest.ProviderName,
}

This is the order used when registering providers and when building the default rules. It is also the order used in error messages — handy when grepping logs.

Loading order

cmd/traefik/traefik.go sets up four loaders in this order:

loaders := []cli.ResourceLoader{
    &tcli.DeprecationLoader{},
    &tcli.FileLoader{},
    &tcli.FlagLoader{},
    &tcli.EnvLoader{},
}

Later loaders override earlier ones. So CLI flags beat the file, environment variables beat CLI flags, and the deprecation loader runs first to remap old field names.

The actual decoding is done by github.com/traefik/paerser, which reflects on the struct tags. Every static-config field declares all four formats:

EntryPoints EntryPoints `description:"…" json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`

Validation

After loading, the binary calls:

staticConfiguration.SetEffectiveConfiguration()
staticConfiguration.ValidateConfiguration()

SetEffectiveConfiguration fills defaults and resolves cross-field implications (e.g. enabling the traefik entry point when API is enabled). ValidateConfiguration rejects logically inconsistent setups (missing entry points, non-routable rules).

Dynamic configuration

pkg/config/dynamic is where routers, services, middlewares, and TLS material live. It is split by protocol:

File Defines
pkg/config/dynamic/http_config.go HTTPConfiguration, Router, Service, LoadBalancerService, WeightedRoundRobin, mirroring, …
pkg/config/dynamic/tcp_config.go TCP variants of the above.
pkg/config/dynamic/udp_config.go UDP variants.
pkg/config/dynamic/middlewares.go All HTTP middleware configuration types (~65k bytes — every middleware lives here).
pkg/config/dynamic/tcp_middlewares.go TCP middleware types.
pkg/config/dynamic/config.go Configuration and Message envelopes used by providers.

The top-level type providers emit is dynamic.Configuration, which contains HTTP, TCP, UDP, and TLS sub-configurations. Providers wrap that into dynamic.Message{ProviderName, Configuration} and push it onto a channel.

Configuration messages

type Message struct {
    ProviderName  string
    Configuration *Configuration
}

The ProviderName is required because the watcher deduplicates per provider. Two different providers can produce overlapping configurations — the watcher merges them into a single snapshot before dispatching.

Deepcopy

Configuration types implement deepcopy so callers can freely mutate snapshots. The deepcopy functions live in pkg/config/dynamic/zz_generated.deepcopy.go (78k bytes, generated by controller-gen). Don't edit by hand; run make generate-crd after changing types.

Runtime configuration

pkg/config/runtime is the dynamic configuration plus per-object status. It is the model the dashboard sees.

type Configuration struct {
    Routers     map[string]*RouterInfo
    Middlewares map[string]*MiddlewareInfo
    Services    map[string]*ServiceInfo
    TCPRouters  map[string]*TCPRouterInfo
    // ...
}

type RouterInfo struct {
    *dynamic.Router
    Err    []string
    Status string
    Using  []string
}

Status is one of enabled, disabled, or warning. Err carries the human-readable reason. The runtime configuration is built each apply by pkg/server/router/router.go and read by pkg/api/handler.go.

The configuration watcher

pkg/server/configurationwatcher.go ties providers to the router factory.

type ConfigurationWatcher struct {
    providerAggregator        provider.Provider
    defaultEntryPoints        []string
    allProvidersConfigs       chan dynamic.Message
    newConfigs                chan dynamic.Configurations
    requiredProvider          string
    configurationListeners    []func(dynamic.Configuration)
    configurationTransformers []func(context.Context, dynamic.Configurations) dynamic.Configurations
    routinesPool              *safe.Pool
}

Three goroutines run inside Start:

  1. startProviderAggregator — calls providerAggregator.Provide(c.allProvidersConfigs, c.routinesPool) to fan in messages from every configured provider.
  2. receiveConfigurations — reads from allProvidersConfigs, deduplicates per provider, applies transformers, and sends the merged snapshot to newConfigs non-blockingly.
  3. applyConfigurations — reads the latest snapshot from newConfigs and calls each registered listener.

The non-blocking send into newConfigs is what guarantees that if a burst of provider messages arrives, only the latest one is applied. Older snapshots in flight get dropped, never queued.

Listeners

Listeners are registered via AddListener. Two are always present:

  • The router factory listener (pkg/server/routerfactory.go), which rebuilds the live router tree.
  • The TLS manager listener (pkg/tls/tlsmanager.go), which updates the certificate store.

Plugins that ship with Traefik (e.g. Hub) attach themselves as transformers — they get a chance to mutate the configuration before listeners see it.

Provider aggregator

pkg/provider/aggregator/aggregator.go is a provider.Provider that fans out across multiple inner providers. It owns:

  • internalProvider — the implicit traefik provider that injects required routers (e.g. for the dashboard).
  • fileProvider — the file/directory provider, present even if the user didn't configure it (it backs the defaultRule infrastructure for some integrations).
  • All user-configured providers from the static config.
  • Optional Hub-related providers wrapped at the edges.

Provide runs each inner provider in its own goroutine via the routinesPool. Each inner provider's messages get tagged with its ProviderName before flowing into the aggregator's output channel. This is what gives the watcher the per-provider deduplication key.

Practical implications

  • To add a configuration field: edit the matching struct in pkg/config/static or pkg/config/dynamic, add tags for every format, run make generate generate-crd.
  • To change configuration application semantics: it's almost always the watcher loop in configurationwatcher.go. Mind the channel ordering and the listener contract.
  • To debug "why isn't my change applying?": enable --log.level=DEBUG and look for "Skipping unchanged configuration" or listener-side errors.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Configuration – Traefik wiki | Factory