docs/content/migrate/v3.md
This guide provides detailed migration steps for upgrading between different Traefik v3 versions. Each section covers breaking changes, deprecations, and configuration updates required for a smooth transition.
Starting with v3.1, Traefik's Kubernetes Providers use the EndpointSlices API (requires Kubernetes >=v1.21) for service endpoint discovery. This change also introduces NodePort load-balancing capabilities.
The following RBAC updates are required for all Kubernetes providers:
# Remove this section from your RBAC
# - apiGroups: [""]
# resources: ["endpoints"]
# verbs: ["get", "list", "watch"]
# Add this section instead
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
!!! note "Affected Providers" These changes apply to:
- [KubernetesIngress](../reference/install-configuration/providers/kubernetes/kubernetes-ingress.md) provider
- [KubernetesCRD](../reference/install-configuration/providers/kubernetes/kubernetes-crd.md#requirements) provider
- [KubernetesGateway](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#requirements) provider
The KubernetesGateway Provider is no longer experimental in v3.1 and can be enabled without the experimental.kubernetesgateway option.
Deprecated Configuration:
??? example "Experimental kubernetesgateway option (deprecated)"
```yaml tab="File (YAML)"
experimental:
kubernetesgateway: true
```
```toml tab="File (TOML)"
[experimental]
kubernetesgateway=true
```
```bash tab="CLI"
--experimental.kubernetesgateway=true
```
Migration Steps:
kubernetesgateway option from the experimental sectionThe disableIngressClassLookup option has been deprecated and will be removed in the next major version.
Migration Required:
disableIngressClassLookupdisableClusterScopeResourcesThe new option provides broader control over cluster scope resources discovery, including both IngressClass and Nodes resources.
New optional fields have been added to several CRDs. These updates are backward compatible and only add new functionality.
Apply the latest CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.3/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
Updated Resources:
Starting with v3.2, the Kubernetes Gateway Provider now supports GRPCRoute resources.
Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs),
the grcroutes and grpcroutes/status rights have to be added.
Required RBAC Updates:
...
- apiGroups:
- gateway.networking.k8s.io
resources:
- grpcroutes
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- grpcroutes/status
verbs:
- update
...
Due to breaking changes in Kubernetes Gateway v1.2.0-rc1, Traefik v3.3 only supports Kubernetes Gateway v1.2.x when experimental features are enabled.
New Feature: BackendTLSPolicy Support
The provider now supports BackendTLSPolicy resources.
Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs),
the backendtlspolicies and backendtlspolicies/status rights have to be added.
Required RBAC Updates:
...
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- backendtlspolicies
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- backendtlspolicies/status
verbs:
- update
...
X-Forwarded-Prefix Header ChangesIn v3.2.1, the X-Forwarded-Prefix header is now handled like other X-Forwarded-* headers - Traefik removes it when sent from untrusted sources.
This change improves security by preventing header spoofing from untrusted clients. Refer to the Forwarded headers documentation for configuration details.
In v3.2.2, Swarm-specific labels have been deprecated and will be removed in a future version.
Migration Required:
| Deprecated Label | New Label |
|---|---|
traefik.docker.network | traefik.swarm.network |
traefik.docker.lbswarm | traefik.swarm.lbswarm |
In v3.3, DNS challenge configuration options have been reorganized for better clarity.
Migration Required:
| Deprecated Option | New Option |
|---|---|
acme.dnsChallenge.delaybeforecheck | acme.dnsChallenge.propagation.delayBeforeChecks |
acme.dnsChallenge.disablepropagationcheck | acme.dnsChallenge.propagation.disableChecks |
In v3.3, the tracing configuration has been clarified to better reflect its purpose.
Migration Required:
tracing.globalAttributestracing.resourceAttributesThe old option name was misleading as it specifically adds resource attributes for the collector, not global span attributes.
In v3.3.4, the OpenTelemetry Request Duration metric unit has been standardized to match other providers and naming conventions.
Change Details:
traefik_(entrypoint|router|service)_request_duration_secondsThis change ensures consistency across all metrics providers and follows standard naming conventions.
In v3.3.5, the default compression algorithms have been reordered to favor gzip compression.
New Default: gzip, br, zstd
This change affects requests that either:
Accept-Encoding headerAccept-Encoding headerThe reordering helps ensure better compatibility with older clients that may not support newer compression algorithms.
Starting with v3.3.6, incoming request paths are now automatically cleaned before processing for security and consistency.
What's Changed:
The following path segments are now interpreted and collapsed:
/../ (parent directory references)/./ (current directory references)//)Disabling Sanitization:
# EntryPoint HTTP configuration
entryPoints:
web:
address: ":80"
http:
sanitizePath: false # Not recommended
!!! danger "Security Warning"
Setting sanitizePath: false is not safe. This option should only be used with legacy clients that don't properly URL-encode data. Always ensure requests are properly URL-encoded instead of disabling this security feature.
Example Risk: Base64 data containing "/" characters can lead to unsafe routing when path sanitization is disabled and the data isn't URL-encoded.
Starting with v3.4, HTTP service definitions now support additional load-balancing strategies for better traffic distribution.
Apply Updated CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
New Strategy Values:
wrr (Weighted Round Robin)p2c (Power of Two Choices)!!! warning "Deprecation"
The RoundRobin strategy is deprecated but still supported (equivalent to wrr). It will be removed in the next major release.
Refer to the HTTP Services Load Balancing documentation for detailed information.
A new rootCAs option has been added to the ServersTransport and ServersTransportTCP CRDs. It supports both ConfigMaps and Secrets for CA certificates and replaces the rootCAsSecrets option.
Apply Updates:
# Update CRDs
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
# Update RBACs
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
New Configuration Format:
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: foo
namespace: bar
spec:
rootCAs:
- configMap: ca-config-map
- secret: ca-secret
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransportTCP
metadata:
name: foo
namespace: bar
spec:
rootCAs:
- configMap: ca-config-map
- secret: ca-secret
!!! warning "Deprecation"
The rootCAsSecrets option (Secrets only) is still supported but deprecated. It will be removed in the next major release.
In v3.4, rule syntax configuration options will be removed in the next major version.
Deprecated Options:
core.defaultRuleSyntax (static configuration)ruleSyntax (router option)These options were transitional helpers for migrating from v2 to v3 syntax. Please ensure all router rules use v3 syntax before the next major release.
Starting with v3.4.1, request paths are now normalized according to RFC 3986 standards for better consistency and security.
Normalization Process:
%2E (.) are decoded to their literal form%2e becomes %2E)This follows RFC 3986 percent-encoding normalization and case normalization standards.
Processing Order:
Starting with v3.4.1, reserved characters (per RFC 3986) remain encoded during router rule matching to prevent routing ambiguity.
Why This Matters: Reserved characters change the meaning of request paths when decoded. Keeping them encoded during routing prevents security vulnerabilities and ensures predictable routing behavior.
The following table illustrates how path matching behavior has changed:
| Request Path | Router Rule | Traefik v3.4.0 | Traefik v3.4.1 | Explanation |
|---|---|---|---|---|
/foo%2Fbar | PathPrefix(`/foo/bar`) | Match | No match | %2F (/) stays encoded, preventing false matches |
/foo/../bar | PathPrefix(`/foo`) | No match | No match | Path traversal is sanitized away |
/foo/../bar | PathPrefix(`/bar`) | Match | Match | Resolves to /bar after sanitization |
/foo/%2E%2E/bar | PathPrefix(`/foo`) | Match | No match | Encoded dots normalized then sanitized |
/foo/%2E%2E/bar | PathPrefix(`/bar`) | No match | Match | Resolves to /bar after normalization + sanitization |
Since v3.4.5, the MultiPath TCP support introduced with v3.4.2 has been removed.
It appears that enabling MPTCP on some platforms can cause Traefik to stop with the following error logs message:
set tcp X.X.X.X:X->X.X.X.X:X: setsockopt: operation not supportedHowever, it can be re-enabled by setting the multipathtcp variable in the GODEBUG environment variable, see the related go documentation.
Starting with v3.5.0, a new traceVerbosity option is available for both entrypoints and routers.
This option allows you to control the level of detail for tracing spans.
Routers can override the value inherited from their entrypoint.
Impact:
minimal unless overridden, which will result in fewer spans being generated than before.Possible values are:
minimal: produces a single server span and one client span for each request processed by a router.detailed: enables the creation of additional spans for each middleware executed for each request processed by a router.See the updated documentation for entrypoints and dynamic routers.
Since v3.5.0, the semconv attributes k8s.pod.name and k8s.pod.uid are injected automatically in OTel resource attributes when OTel tracing/logs/metrics are enabled.
For that purpose, the following right has to be added to the Traefik Kubernetes RBACs:
...
- apiGroups:
- ""
resources:
- pods
verbs:
- get
...
Starting with v3.5.2, the proxyProtocol option for TCP LoadBalancer is deprecated.
This option can now be configured at the TCPServersTransport level, please check out the documentation for more details.
To use the new proxyprotocol option in the Kubernetes CRD provider, you need to update your CRDs.
Apply Updated CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.5/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
Starting with v3.5.4, and when using OpenTelemetry, the traefik_tls_certs_not_after_milliseconds metric is renamed to traefik_tls_certs_not_after_seconds.
This change aligns the metric name with its real unit precision, which is in seconds.
Starting with v3.6.0, the Kubernetes Gateway API provider only supports version v1.4.0 of the specification,
which requires the Gateway API CRDs to be updated.
Apply Updated CRDs:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
For the experimental channel:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml
To use the new leasttime load-balancer algorithm with the Kubernetes CRD provider, you need to update your CRDs.
Apply Updated CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
The KubernetesIngressNGINX Provider is no longer experimental in v3.6.2 and can be enabled without the experimental.kubernetesIngressNGINX option.
Deprecated Configuration:
??? example "Experimental kubernetesIngressNGINX option (deprecated)"
```yaml tab="File (YAML)"
experimental:
kubernetesIngressNGINX: true
```
```toml tab="File (TOML)"
[experimental]
kubernetesIngressNGINX=true
```
```bash tab="CLI"
--experimental.kubernetesIngressNGINX=true
```
Migration Steps:
kubernetesIngressNGINX option from the experimental sectionStarting with v3.6.4, for security reasons, Traefik now rejects requests with a path containing a specific set of encoded characters by default.
When such a request is received, Traefik responds with a 400 Bad Request status code.
Here is the list of the encoded characters that are rejected by default, along with the corresponding configuration option to allow them:
| Encoded Character | Character | Config option to allow the encoded character |
|---|---|---|
%2f or %2F | / (slash) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedSlash | ||
%5c or %5C | \ (backslash) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedBackSlash | ||
%00 | NULL (null character) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedNullCharacter | ||
%3b or %3B | ; (semicolon) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedSemicolon | ||
%25 | % (percent) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedPercent | ||
%3f or %3F | ? (question mark) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedQuestionMark | ||
%23 | # (hash) | entryPoints.<name> |
.http.encodedCharacters | ||
.allowEncodedHash |
Please check out the entrypoint encodedCharacters option documentation for more details.
Since v3.6.7, the options for encoded characters now have a true default value.
This means that Traefik will not reject requests with a path containing a specific set of encoded characters by default.
It is now up to the users to configure the security hardening of encoded characters.
Here is the list of the encoded characters that can be configured to false to disallow them:
| Encoded Character | Character | Config options | Default value |
|---|---|---|---|
%2f or %2F | / (slash) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedSlash | true | ||
%5c or %5C | \ (backslash) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedBackSlash | true | ||
%00 | NULL (null character) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedNullCharacter | true | ||
%3b or %3B | ; (semicolon) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedSemicolon | true | ||
%25 | % (percent) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedPercent | true | ||
%3f or %3F | ? (question mark) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedQuestionMark | true | ||
%23 | # (hash) | entryPoints.<name> | |
.http.encodedCharacters | |||
.allowEncodedHash | true |
Note: This check is not done against query parameters, but only against the request path as defined in RFC3986 section-3.
Please check out the entrypoint encodedCharacters option documentation for more details.
Since v3.6.8, the configured path for the health check request is now verified to be a relative URL, and the health check will fail if it is not.
maxResponseBodySize configuration on ForwardAuth middlewareIn v3.6.9, a new maxResponseBodySize option has been added to the ForwardAuth middleware configuration.
The default value for this option is -1, which means there is no limit to the response body size.
However, it is strongly recommended to set this option to a suitable value to avoid performance and security issues,
such as DoS attacks and memory exhaustion.
Please check out the ForwardAuth middleware documentation for more details.
To use the new maxResponseBodySize option in the ForwardAuth middleware with the Kubernetes CRD provider, you need to update your CRDs.
Apply Updated CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
Starting with v3.7.0, the Ingress NGINX provider now supports the nginx.ingress.kubernetes.io/custom-headers annotation to add custom headers to the response forwarded to the client.
Therefore, in the corresponding RBACs (see KubernetesIngressNGINX provider RBACs) the configmaps right has been added.
Required RBAC Updates:
...
- apiGroups:
- ""
resources:
- configmaps
verbs:
- list
- watch
...
Starting with v3.7.0, the Kubernetes Gateway API provider supports version v1.5.1 of the specification,
which requires the Gateway API CRDs to be updated.
TLSRoute has graduated to the Standard channel and no longer requires the experimentalChannel option.
The experimentalChannel option is now only needed for TCPRoute.
Apply Updated CRDs:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
For the experimental channel:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/experimental-install.yaml
To use the new options of the retry middleware with the Kubernetes CRD provider, you need to update your CRDs.
Apply Updated CRDs:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml