mirror of
https://github.com/traefik/traefik.git
synced 2026-03-01 03:31:20 +01:00
Merge branch v3.6 into master
This commit is contained in:
commit
f0da74e641
58
CHANGELOG.md
58
CHANGELOG.md
@ -1,3 +1,61 @@
|
||||
## [v3.6.8](https://github.com/traefik/traefik/tree/v3.6.8) (2026-02-11)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.6.7...v3.6.8)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Remove invalid private key in log ([#12574](https://github.com/traefik/traefik/pull/12574) by [juliens](https://github.com/juliens))
|
||||
- **[acme]** Alter TLS renewal period ([#12479](https://github.com/traefik/traefik/pull/12479) by [LtHummus](https://github.com/LtHummus))
|
||||
- **[healthcheck]** Reject absolute URL in healthcheck path configuration ([#12653](https://github.com/traefik/traefik/pull/12653) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.0 ([#12553](https://github.com/traefik/traefik/pull/12553) by [jnoordsij](https://github.com/jnoordsij))
|
||||
- **[metrics,tracing,accesslogs]** Fix ObservabilityConfig SetDefaults ([#12636](https://github.com/traefik/traefik/pull/12636) by [mmatur](https://github.com/mmatur))
|
||||
- **[server]** Remove conn deadline after STARTTLS negociation ([#12639](https://github.com/traefik/traefik/pull/12639) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[tls]** Fix verifyServerCertMatchesURI function behavior ([#12575](https://github.com/traefik/traefik/pull/12575) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[tracing,otel]** Use ParentBased sampler to respect parent span sampling decision ([#12403](https://github.com/traefik/traefik/pull/12403) by [xe-leon](https://github.com/xe-leon))
|
||||
- **[webui]** Use url.Parse to validate X-Forwarded-Prefix value ([#12643](https://github.com/traefik/traefik/pull/12643) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[healthcheck]** Validate healthcheck path configuration (#12642 by @rtribotte)
|
||||
- **[tls, server]** Cap TLS record length to RFC 8446 limit in ClientHello peeking (#12638 by @mmatur)
|
||||
- **[service]** Avoid recursion with services ([#12591](https://github.com/traefik/traefik/pull/12591) by [juliens](https://github.com/juliens))
|
||||
- **[webui]** Bump dependencies of documentation and webui ([#12581](https://github.com/traefik/traefik/pull/12581) by [gndz07](https://github.com/gndz07))
|
||||
|
||||
**Documentation:**
|
||||
- **[k8s]** Fix kubernetes.md with correct http redirections ([#12603](https://github.com/traefik/traefik/pull/12603) by [MartenM](https://github.com/MartenM))
|
||||
- **[middleware,k8s/crd]** Fix the errors middleware's document for Kubernetes CRD ([#12600](https://github.com/traefik/traefik/pull/12600) by [yuito-it](https://github.com/yuito-it))
|
||||
- **[tls]** Clarify SNI selection ([#12482](https://github.com/traefik/traefik/pull/12482) by [AnuragEkkati](https://github.com/AnuragEkkati))
|
||||
- Fix typo on JWT documentation ([#12616](https://github.com/traefik/traefik/pull/12616) by [mdevino](https://github.com/mdevino))
|
||||
- Add @gndz07 as a current maintainer ([#12594](https://github.com/traefik/traefik/pull/12594) by [emilevauge](https://github.com/emilevauge))
|
||||
- Remove extraneous dots in migration guide ([#12571](https://github.com/traefik/traefik/pull/12571) by [dathbe](https://github.com/dathbe))
|
||||
- Document Path matcher placeholder removal in v3 migration guide ([#12570](https://github.com/traefik/traefik/pull/12570) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- Improve Service Reference page ([#12541](https://github.com/traefik/traefik/pull/12541) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- Document negative priority support for routers ([#12505](https://github.com/traefik/traefik/pull/12505) by [understood-the-assignment](https://github.com/understood-the-assignment))
|
||||
- Improve the structure of the routing reference pages ([#12429](https://github.com/traefik/traefik/pull/12429) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- Clean Up Menu Entries & Update Expose Overview ([#12405](https://github.com/traefik/traefik/pull/12405) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- Split Expose User Guides & Add Multi-Layer Routing Section ([#12238](https://github.com/traefik/traefik/pull/12238) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- Remove extra dots in migration guide ([#12573](https://github.com/traefik/traefik/pull/12573) by [rtribotte](https://github.com/rtribotte))
|
||||
|
||||
**Misc:**
|
||||
- Merge v2.11 into v3.6 ([#12652](https://github.com/traefik/traefik/pull/12652) by [mmatur](https://github.com/mmatur))
|
||||
- Merge v2.11 into v3.6 ([#12644](https://github.com/traefik/traefik/pull/12644) by [mmatur](https://github.com/mmatur))
|
||||
- Merge branch v2.11 into v3.6 ([#12617](https://github.com/traefik/traefik/pull/12617) by [mmatur](https://github.com/mmatur))
|
||||
- Merge v2.11 into v3.6 ([#12605](https://github.com/traefik/traefik/pull/12605) by [mmatur](https://github.com/mmatur))
|
||||
- Merge v2.11 into v3.6 ([#12601](https://github.com/traefik/traefik/pull/12601) by [mmatur](https://github.com/mmatur))
|
||||
- Merge branch v2.11 into v3.6 ([#12556](https://github.com/traefik/traefik/pull/12556) by [mmatur](https://github.com/mmatur))
|
||||
|
||||
## [v2.11.37](https://github.com/traefik/traefik/tree/v2.11.37) (2026-02-11)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.36...v2.11.37)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[healthcheck]** Validate healthcheck path configuration (#12642 by @rtribotte)
|
||||
- **[tls, server]** Cap TLS record length to RFC 8446 limit in ClientHello peeking (#12638 by @mmatur)
|
||||
|
||||
## [v2.11.36](https://github.com/traefik/traefik/tree/v2.11.36) (2026-02-02)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.35...v2.11.36)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[service]** Avoid recursion with services ([#12591](https://github.com/traefik/traefik/pull/12591) by [juliens](https://github.com/juliens))
|
||||
- **[webui]** Bump dependencies of documentation and webui ([#12581](https://github.com/traefik/traefik/pull/12581) by [gndz07](https://github.com/gndz07))
|
||||
|
||||
**Documentation:**
|
||||
- Remove extra dots in migration guide ([#12573](https://github.com/traefik/traefik/pull/12573) by [rtribotte](https://github.com/rtribotte))
|
||||
|
||||
## [v3.6.7](https://github.com/traefik/traefik/tree/v3.6.7) (2026-01-14)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.6.6...v3.6.7)
|
||||
|
||||
|
||||
4
docs/content/assets/css/content-width.css
Normal file
4
docs/content/assets/css/content-width.css
Normal file
@ -0,0 +1,4 @@
|
||||
/* Use a wider grid to accommodate table content and code blocks. */
|
||||
.md-grid {
|
||||
max-width: 1650px;
|
||||
}
|
||||
@ -604,6 +604,12 @@ in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation
|
||||
for more details.
|
||||
|
||||
## v3.6.8
|
||||
|
||||
### Health Check Request Path
|
||||
|
||||
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.
|
||||
|
||||
## v3.7.0
|
||||
|
||||
### Ingress NGINX Provider
|
||||
|
||||
@ -290,13 +290,13 @@ See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
kubernetesGateway:
|
||||
labelselector: "app=traefik"
|
||||
labelSelector: "app=traefik"
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.kubernetesGateway]
|
||||
labelselector = "app=traefik"
|
||||
labelSelector = "app=traefik"
|
||||
# ...
|
||||
```
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ The provider then watches for incoming Knative events and derives the correspond
|
||||
| <a id="opt-providers-knative-token" href="#opt-providers-knative-token" title="#opt-providers-knative-token">providers.knative.token</a> | Bearer token used for the Kubernetes client configuration. | |
|
||||
| <a id="opt-providers-knative-certauthfilepath" href="#opt-providers-knative-certauthfilepath" title="#opt-providers-knative-certauthfilepath">providers.knative.certauthfilepath</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | |
|
||||
| <a id="opt-providers-knative-namespaces" href="#opt-providers-knative-namespaces" title="#opt-providers-knative-namespaces">providers.knative.namespaces</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | |
|
||||
| <a id="opt-providers-knative-labelselector" href="#opt-providers-knative-labelselector" title="#opt-providers-knative-labelselector">providers.knative.labelselector</a> | Allow filtering Knative Ingress objects using label selectors. | |
|
||||
| <a id="opt-providers-knative-labelSelector" href="#opt-providers-knative-labelSelector" title="#opt-providers-knative-labelSelector">providers.knative.labelSelector</a> | Allow filtering Knative Ingress objects using label selectors. | |
|
||||
| <a id="opt-providers-knative-throttleduration" href="#opt-providers-knative-throttleduration" title="#opt-providers-knative-throttleduration">providers.knative.throttleduration</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0 |
|
||||
| <a id="opt-providers-knative-privateentrypoints" href="#opt-providers-knative-privateentrypoints" title="#opt-providers-knative-privateentrypoints">providers.knative.privateentrypoints</a> | Entrypoint names used to expose the Ingress privately. If empty local Ingresses are skipped. | |
|
||||
| <a id="opt-providers-knative-privateservice" href="#opt-providers-knative-privateservice" title="#opt-providers-knative-privateservice">providers.knative.privateservice</a> | Kubernetes service used to expose the networking controller privately. | |
|
||||
|
||||
@ -59,7 +59,7 @@ providers:
|
||||
| <a id="opt-providers-kubernetesCRD-token" href="#opt-providers-kubernetesCRD-token" title="#opt-providers-kubernetesCRD-token">`providers.kubernetesCRD.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesCRD-certAuthFilePath" href="#opt-providers-kubernetesCRD-certAuthFilePath" title="#opt-providers-kubernetesCRD-certAuthFilePath">`providers.kubernetesCRD.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesCRD-namespaces" href="#opt-providers-kubernetesCRD-namespaces" title="#opt-providers-kubernetesCRD-namespaces">`providers.kubernetesCRD.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | [] | No |
|
||||
| <a id="opt-providers-kubernetesCRD-labelselector" href="#opt-providers-kubernetesCRD-labelselector" title="#opt-providers-kubernetesCRD-labelselector">`providers.kubernetesCRD.labelselector`</a> | Allow filtering on specific resource objects only using label selectors.<br />Only to Traefik [Custom Resources](#list-of-resources) (they all must match the filter).<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesCRD-labelSelector" href="#opt-providers-kubernetesCRD-labelSelector" title="#opt-providers-kubernetesCRD-labelSelector">`providers.kubernetesCRD.labelSelector`</a> | Allow filtering on specific resource objects only using label selectors.<br />Only to Traefik [Custom Resources](#list-of-resources) (they all must match the filter).<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesCRD-ingressClass" href="#opt-providers-kubernetesCRD-ingressClass" title="#opt-providers-kubernetesCRD-ingressClass">`providers.kubernetesCRD.ingressClass`</a> | Value of `spec.ingressClassName` field (or the deprecated `kubernetes.io/ingress.class` annotation) that identifies resource objects to be processed.<br />If empty, resources missing the field/annotation, having an empty value, or the value `traefik` are processed.<br />The `spec.ingressClassName` field takes precedence over the annotation. | "" | No |
|
||||
| <a id="opt-providers-kubernetesCRD-throttleDuration" href="#opt-providers-kubernetesCRD-throttleDuration" title="#opt-providers-kubernetesCRD-throttleDuration">`providers.kubernetesCRD.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
|
||||
| <a id="opt-providers-kubernetesCRD-allowEmptyServices" href="#opt-providers-kubernetesCRD-allowEmptyServices" title="#opt-providers-kubernetesCRD-allowEmptyServices">`providers.kubernetesCRD.allowEmptyServices`</a> | Allows creating a route to reach a service that has no endpoint available.<br />It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a `503` HTTP Status. | false | No |
|
||||
|
||||
@ -75,7 +75,7 @@ providers:
|
||||
| <a id="opt-providers-kubernetesGateway-token" href="#opt-providers-kubernetesGateway-token" title="#opt-providers-kubernetesGateway-token">`providers.kubernetesGateway.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-certAuthFilePath" href="#opt-providers-kubernetesGateway-certAuthFilePath" title="#opt-providers-kubernetesGateway-certAuthFilePath">`providers.kubernetesGateway.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-namespaces" href="#opt-providers-kubernetesGateway-namespaces" title="#opt-providers-kubernetesGateway-namespaces">`providers.kubernetesGateway.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | [] | No |
|
||||
| <a id="opt-providers-kubernetesGateway-labelselector" href="#opt-providers-kubernetesGateway-labelselector" title="#opt-providers-kubernetesGateway-labelselector">`providers.kubernetesGateway.labelselector`</a> | Allow filtering on specific resource objects only using label selectors.<br />Only to Traefik [Custom Resources](./kubernetes-crd.md#list-of-resources) (they all must match the filter).<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-labelSelector" href="#opt-providers-kubernetesGateway-labelSelector" title="#opt-providers-kubernetesGateway-labelSelector">`providers.kubernetesGateway.labelSelector`</a> | Allow filtering on specific resource objects only using label selectors.<br />Only to Traefik [Custom Resources](./kubernetes-crd.md#list-of-resources) (they all must match the filter).<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-throttleDuration" href="#opt-providers-kubernetesGateway-throttleDuration" title="#opt-providers-kubernetesGateway-throttleDuration">`providers.kubernetesGateway.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
|
||||
| <a id="opt-providers-kubernetesGateway-nativeLBByDefault" href="#opt-providers-kubernetesGateway-nativeLBByDefault" title="#opt-providers-kubernetesGateway-nativeLBByDefault">`providers.kubernetesGateway.nativeLBByDefault`</a> | Defines whether to use Native Kubernetes load-balancing mode by default. For more information, please check out the `traefik.io/service.nativelb` service annotation documentation. | false | No |
|
||||
| <a id="opt-providers-kubernetesGateway-statusAddress-hostname" href="#opt-providers-kubernetesGateway-statusAddress-hostname" title="#opt-providers-kubernetesGateway-statusAddress-hostname">`providers.kubernetesGateway.`<br />`statusAddress.hostname`</a> | Hostname copied to the Gateway `status.addresses`. | "" | No |
|
||||
|
||||
@ -52,7 +52,7 @@ which in turn creates the resulting routers, services, handlers, etc.
|
||||
| <a id="opt-providers-kubernetesIngress-token" href="#opt-providers-kubernetesIngress-token" title="#opt-providers-kubernetesIngress-token">`providers.kubernetesIngress.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngress-certAuthFilePath" href="#opt-providers-kubernetesIngress-certAuthFilePath" title="#opt-providers-kubernetesIngress-certAuthFilePath">`providers.kubernetesIngress.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngress-namespaces" href="#opt-providers-kubernetesIngress-namespaces" title="#opt-providers-kubernetesIngress-namespaces">`providers.kubernetesIngress.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | | No |
|
||||
| <a id="opt-providers-kubernetesIngress-labelselector" href="#opt-providers-kubernetesIngress-labelselector" title="#opt-providers-kubernetesIngress-labelselector">`providers.kubernetesIngress.labelselector`</a> | Allow filtering on Ingress objects using label selectors.<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngress-labelSelector" href="#opt-providers-kubernetesIngress-labelSelector" title="#opt-providers-kubernetesIngress-labelSelector">`providers.kubernetesIngress.labelSelector`</a> | Allow filtering on Ingress objects using label selectors.<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngress-ingressClass" href="#opt-providers-kubernetesIngress-ingressClass" title="#opt-providers-kubernetesIngress-ingressClass">`providers.kubernetesIngress.ingressClass`</a> | The `IngressClass` resource name or the `kubernetes.io/ingress.class` annotation value that identifies resource objects to be processed.<br />If empty, resources missing the annotation, having an empty value, or the value `traefik` are processed. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngress-disableIngressClassLookup" href="#opt-providers-kubernetesIngress-disableIngressClassLookup" title="#opt-providers-kubernetesIngress-disableIngressClassLookup">`providers.kubernetesIngress.disableIngressClassLookup`</a> | Prevent to discover IngressClasses in the cluster.<br />It alleviates the requirement of giving Traefik the rights to look IngressClasses up.<br />Ignore Ingresses with IngressClass.<br />Annotations are not affected by this option. | false | No |
|
||||
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-hostname" href="#opt-providers-kubernetesIngress-ingressEndpoint-hostname" title="#opt-providers-kubernetesIngress-ingressEndpoint-hostname">`providers.kubernetesIngress.`<br />`ingressEndpoint.hostname`</a> | Hostname used for Kubernetes Ingress endpoints. | "" | No |
|
||||
|
||||
@ -292,9 +292,9 @@ To propagate status changes (e.g. all servers of this service are down) upwards,
|
||||
|
||||
Below are the available options for the health check mechanism:
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|---------------------|-------------------------------------------------------------------------------------------------------------------------------|---------|----------|
|
||||
| <a id="opt-path" href="#opt-path" title="#opt-path">`path`</a> | Defines the server URL path for the health check endpoint. | "" | Yes |
|
||||
| Field | Description | Default | Required |
|
||||
|--------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------|----------|
|
||||
| <a id="opt-path" href="#opt-path" title="#opt-path">`path`</a> | Defines the server URL path for the health check endpoint. The configured path must be relative URL. | "" | Yes |
|
||||
| <a id="opt-scheme" href="#opt-scheme" title="#opt-scheme">`scheme`</a> | Replaces the server URL scheme for the health check endpoint. | | No |
|
||||
| <a id="opt-mode" href="#opt-mode" title="#opt-mode">`mode`</a> | If defined to `grpc`, will use the gRPC health check protocol to probe the server. | http | No |
|
||||
| <a id="opt-hostname" href="#opt-hostname" title="#opt-hostname">`hostname`</a> | Defines the value of hostname in the Host header of the health check request. | "" | No |
|
||||
|
||||
@ -80,36 +80,36 @@ spec:
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:---------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------|:---------|
|
||||
| <a id="opt-kind" href="#opt-kind" title="#opt-kind">`kind`</a> | Kind of the service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br /> **TraefikService**: Traefik Service.<br />More information [here](#externalname-service). | "Service" | No |
|
||||
| <a id="opt-name" href="#opt-name" title="#opt-name">`name`</a> | Service name.<br />The character `@` is not authorized. <br />More information [here](#middleware). | | Yes |
|
||||
| <a id="opt-namespace" href="#opt-namespace" title="#opt-namespace">`namespace`</a> | Service namespace.<br />Can be empty if the service belongs to the same namespace as the IngressRoute. <br />More information [here](#externalname-service). | | No |
|
||||
| <a id="opt-port" href="#opt-port" title="#opt-port">`port`</a> | Service port (number or port name).<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| <a id="opt-responseForwarding-flushInterval" href="#opt-responseForwarding-flushInterval" title="#opt-responseForwarding-flushInterval">`responseForwarding.`<br />`flushInterval`</a> | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind is **Service**. | 100ms | No |
|
||||
| <a id="opt-scheme" href="#opt-scheme" title="#opt-scheme">`scheme`</a> | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| <a id="opt-serversTransport" href="#opt-serversTransport" title="#opt-serversTransport">`serversTransport`</a> | Name of ServersTransport resource to use to configure the transport between Traefik and your servers.<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-passHostHeader" href="#opt-passHostHeader" title="#opt-passHostHeader">`passHostHeader`</a> | Forward client Host header to server.<br />Evaluated only if the kind is **Service**. | true | No |
|
||||
| <a id="opt-healthCheck-scheme" href="#opt-healthCheck-scheme" title="#opt-healthCheck-scheme">`healthCheck.scheme`</a> | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-mode" href="#opt-healthCheck-mode" title="#opt-healthCheck-mode">`healthCheck.mode`</a> | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "http" | No |
|
||||
| <a id="opt-healthCheck-path" href="#opt-healthCheck-path" title="#opt-healthCheck-path">`healthCheck.path`</a> | Server URL path for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-interval" href="#opt-healthCheck-interval" title="#opt-healthCheck-interval">`healthCheck.interval`</a> | Frequency of the health check calls for healthy targets.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "100ms" | No |
|
||||
| <a id="opt-healthCheck-unhealthyInterval" href="#opt-healthCheck-unhealthyInterval" title="#opt-healthCheck-unhealthyInterval">`healthCheck.unhealthyInterval`</a> | Frequency of the health check calls for unhealthy targets.<br />When not defined, it defaults to the `interval` value.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "100ms" | No |
|
||||
| <a id="opt-healthCheck-method" href="#opt-healthCheck-method" title="#opt-healthCheck-method">`healthCheck.method`</a> | HTTP method for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "GET" | No |
|
||||
| <a id="opt-healthCheck-status" href="#opt-healthCheck-status" title="#opt-healthCheck-status">`healthCheck.status`</a> | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| <a id="opt-healthCheck-port" href="#opt-healthCheck-port" title="#opt-healthCheck-port">`healthCheck.port`</a> | URL port for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | | No |
|
||||
| <a id="opt-healthCheck-timeout" href="#opt-healthCheck-timeout" title="#opt-healthCheck-timeout">`healthCheck.timeout`</a> | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "5s" | No |
|
||||
| <a id="opt-healthCheck-hostname" href="#opt-healthCheck-hostname" title="#opt-healthCheck-hostname">`healthCheck.hostname`</a> | Value in the Host header of the health check request.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-followRedirect" href="#opt-healthCheck-followRedirect" title="#opt-healthCheck-followRedirect">`healthCheck.`<br />`followRedirect`</a> | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | true | No |
|
||||
| <a id="opt-healthCheck-headers" href="#opt-healthCheck-headers" title="#opt-healthCheck-headers">`healthCheck.headers`</a> | Map of header to send to the health check endpoint<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service)). | | No |
|
||||
| <a id="opt-sticky-cookie-name" href="#opt-sticky-cookie-name" title="#opt-sticky-cookie-name">`sticky.`<br />`cookie.name`</a> | Name of the cookie used for the stickiness.<br />When sticky sessions are enabled, a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response.<br />On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set.<br />If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-sticky-cookie-httpOnly" href="#opt-sticky-cookie-httpOnly" title="#opt-sticky-cookie-httpOnly">`sticky.`<br />`cookie.httpOnly`</a> | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-sticky-cookie-secure" href="#opt-sticky-cookie-secure" title="#opt-sticky-cookie-secure">`sticky.`<br />`cookie.secure`</a> | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-sticky-cookie-sameSite" href="#opt-sticky-cookie-sameSite" title="#opt-sticky-cookie-sameSite">`sticky.`<br />`cookie.sameSite`</a> | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-sticky-cookie-maxAge" href="#opt-sticky-cookie-maxAge" title="#opt-sticky-cookie-maxAge">`sticky.`<br />`cookie.maxAge`</a> | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind is **Service**. | 0 | No |
|
||||
| <a id="opt-strategy" href="#opt-strategy" title="#opt-strategy">`strategy`</a> | Strategy defines the load balancing strategy between the servers.<br />Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), hrw (Highest Random Weight), and leasttime (Least-Time).<br />Evaluated only if the kind is **Service**. | "RoundRobin" | No |
|
||||
| <a id="opt-nativeLB" href="#opt-nativeLB" title="#opt-nativeLB">`nativeLB`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br /> Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-nodePortLB" href="#opt-nodePortLB" title="#opt-nodePortLB">`nodePortLB`</a> | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| Field | Description | Default | Required |
|
||||
|:---------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------|:---------|
|
||||
| <a id="opt-kind" href="#opt-kind" title="#opt-kind">`kind`</a> | Kind of the service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br /> **TraefikService**: Traefik Service.<br />More information [here](#externalname-service). | "Service" | No |
|
||||
| <a id="opt-name" href="#opt-name" title="#opt-name">`name`</a> | Service name.<br />The character `@` is not authorized. <br />More information [here](#middleware). | | Yes |
|
||||
| <a id="opt-namespace" href="#opt-namespace" title="#opt-namespace">`namespace`</a> | Service namespace.<br />Can be empty if the service belongs to the same namespace as the IngressRoute. <br />More information [here](#externalname-service). | | No |
|
||||
| <a id="opt-port" href="#opt-port" title="#opt-port">`port`</a> | Service port (number or port name).<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| <a id="opt-responseForwarding-flushInterval" href="#opt-responseForwarding-flushInterval" title="#opt-responseForwarding-flushInterval">`responseForwarding.`<br />`flushInterval`</a> | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind is **Service**. | 100ms | No |
|
||||
| <a id="opt-scheme" href="#opt-scheme" title="#opt-scheme">`scheme`</a> | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| <a id="opt-serversTransport" href="#opt-serversTransport" title="#opt-serversTransport">`serversTransport`</a> | Name of ServersTransport resource to use to configure the transport between Traefik and your servers.<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-passHostHeader" href="#opt-passHostHeader" title="#opt-passHostHeader">`passHostHeader`</a> | Forward client Host header to server.<br />Evaluated only if the kind is **Service**. | true | No |
|
||||
| <a id="opt-healthCheck-scheme" href="#opt-healthCheck-scheme" title="#opt-healthCheck-scheme">`healthCheck.scheme`</a> | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-mode" href="#opt-healthCheck-mode" title="#opt-healthCheck-mode">`healthCheck.mode`</a> | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "http" | No |
|
||||
| <a id="opt-healthCheck-path" href="#opt-healthCheck-path" title="#opt-healthCheck-path">`healthCheck.path`</a> | Server URL path for the health check endpoint. <br />The configured path must be relative URL. <br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-interval" href="#opt-healthCheck-interval" title="#opt-healthCheck-interval">`healthCheck.interval`</a> | Frequency of the health check calls for healthy targets.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "100ms" | No |
|
||||
| <a id="opt-healthCheck-unhealthyInterval" href="#opt-healthCheck-unhealthyInterval" title="#opt-healthCheck-unhealthyInterval">`healthCheck.unhealthyInterval`</a> | Frequency of the health check calls for unhealthy targets.<br />When not defined, it defaults to the `interval` value.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "100ms" | No |
|
||||
| <a id="opt-healthCheck-method" href="#opt-healthCheck-method" title="#opt-healthCheck-method">`healthCheck.method`</a> | HTTP method for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "GET" | No |
|
||||
| <a id="opt-healthCheck-status" href="#opt-healthCheck-status" title="#opt-healthCheck-status">`healthCheck.status`</a> | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| <a id="opt-healthCheck-port" href="#opt-healthCheck-port" title="#opt-healthCheck-port">`healthCheck.port`</a> | URL port for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | | No |
|
||||
| <a id="opt-healthCheck-timeout" href="#opt-healthCheck-timeout" title="#opt-healthCheck-timeout">`healthCheck.timeout`</a> | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "5s" | No |
|
||||
| <a id="opt-healthCheck-hostname" href="#opt-healthCheck-hostname" title="#opt-healthCheck-hostname">`healthCheck.hostname`</a> | Value in the Host header of the health check request.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| <a id="opt-healthCheck-followRedirect" href="#opt-healthCheck-followRedirect" title="#opt-healthCheck-followRedirect">`healthCheck.`<br />`followRedirect`</a> | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | true | No |
|
||||
| <a id="opt-healthCheck-headers" href="#opt-healthCheck-headers" title="#opt-healthCheck-headers">`healthCheck.headers`</a> | Map of header to send to the health check endpoint<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service)). | | No |
|
||||
| <a id="opt-sticky-cookie-name" href="#opt-sticky-cookie-name" title="#opt-sticky-cookie-name">`sticky.`<br />`cookie.name`</a> | Name of the cookie used for the stickiness.<br />When sticky sessions are enabled, a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response.<br />On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set.<br />If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-sticky-cookie-httpOnly" href="#opt-sticky-cookie-httpOnly" title="#opt-sticky-cookie-httpOnly">`sticky.`<br />`cookie.httpOnly`</a> | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-sticky-cookie-secure" href="#opt-sticky-cookie-secure" title="#opt-sticky-cookie-secure">`sticky.`<br />`cookie.secure`</a> | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-sticky-cookie-sameSite" href="#opt-sticky-cookie-sameSite" title="#opt-sticky-cookie-sameSite">`sticky.`<br />`cookie.sameSite`</a> | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| <a id="opt-sticky-cookie-maxAge" href="#opt-sticky-cookie-maxAge" title="#opt-sticky-cookie-maxAge">`sticky.`<br />`cookie.maxAge`</a> | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind is **Service**. | 0 | No |
|
||||
| <a id="opt-strategy" href="#opt-strategy" title="#opt-strategy">`strategy`</a> | Strategy defines the load balancing strategy between the servers.<br />Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), hrw (Highest Random Weight), and leasttime (Least-Time).<br />Evaluated only if the kind is **Service**. | "RoundRobin" | No |
|
||||
| <a id="opt-nativeLB" href="#opt-nativeLB" title="#opt-nativeLB">`nativeLB`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br /> Evaluated only if the kind is **Service**. | false | No |
|
||||
| <a id="opt-nodePortLB" href="#opt-nodePortLB" title="#opt-nodePortLB">`nodePortLB`</a> | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
|
||||
|
||||
### ExternalName Service
|
||||
|
||||
@ -439,7 +439,7 @@ To propagate status changes (e.g. all servers of this service are down) upwards,
|
||||
|
||||
Below are the available options for the health check mechanism:
|
||||
|
||||
- `path` (required), defines the server URL path for the health check endpoint .
|
||||
- `path` (required), defines the server URL path for the health check endpoint (must be a relative URL).
|
||||
- `scheme` (optional), replaces the server URL `scheme` for the health check endpoint.
|
||||
- `mode` (default: http), if defined to `grpc`, will use the gRPC health check protocol to probe the server.
|
||||
- `hostname` (optional), sets the value of `hostname` in the `Host` header of the health check request.
|
||||
|
||||
@ -39,6 +39,7 @@ extra_javascript:
|
||||
extra_css:
|
||||
- assets/css/menu-icons.css
|
||||
- assets/css/code-copy.css
|
||||
- assets/css/content-width.css
|
||||
|
||||
plugins:
|
||||
- search
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
@ -75,16 +74,8 @@ func (s *DockerSuite) TestDefaultDockerContainers() {
|
||||
require.NoError(s.T(), err)
|
||||
req.Host = "simple.docker.localhost"
|
||||
|
||||
resp, err := try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
|
||||
_, err = try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDockerContainersWithTCPLabels() {
|
||||
@ -139,16 +130,8 @@ func (s *DockerSuite) TestDockerContainersWithLabels() {
|
||||
require.NoError(s.T(), err)
|
||||
req.Host = "my.super.host"
|
||||
|
||||
resp, err := try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
|
||||
_, err = try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDockerContainersWithOneMissingLabels() {
|
||||
@ -197,17 +180,9 @@ func (s *DockerSuite) TestRestartDockerContainers() {
|
||||
req.Host = "my.super.host"
|
||||
|
||||
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
|
||||
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
|
||||
_, err = try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("powpow"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
services:
|
||||
simple:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blablabla" ]
|
||||
image: traefik/whoami
|
||||
|
||||
withtcplabels:
|
||||
image: traefik/whoamitcp
|
||||
@ -12,26 +11,24 @@ services:
|
||||
traefik.tcp.Services.Super.Loadbalancer.server.port: 8080
|
||||
|
||||
withlabels1:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||
|
||||
withlabels2:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blablabla" ]
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.http.Routers.SuperHost.Rule: Host(`my-super.host`)
|
||||
|
||||
withonelabelmissing:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.random.value: my.super.host
|
||||
|
||||
powpow:
|
||||
image: swarm:1.0.0
|
||||
command: [ "manage", "token://blabla" ]
|
||||
image: traefik/whoami
|
||||
command:
|
||||
- --port=2375
|
||||
labels:
|
||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
@ -80,7 +81,9 @@ func Append(router *mux.Router, basePath string, customAssets fs.FS) error {
|
||||
Path(basePath).
|
||||
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
xfPrefix := req.Header.Get("X-Forwarded-Prefix")
|
||||
if strings.Contains(xfPrefix, "//") {
|
||||
|
||||
// Validates that the X-Forwarded-Prefix value contains a relative URL.
|
||||
if u, err := url.Parse(xfPrefix); err != nil || u.Host != "" || u.Scheme != "" {
|
||||
log.Error().Msgf("X-Forwarded-Prefix contains an invalid value: %s, defaulting to empty prefix", xfPrefix)
|
||||
xfPrefix = ""
|
||||
}
|
||||
|
||||
@ -246,6 +246,15 @@ func (shc *ServiceHealthChecker) checkHealthHTTP(ctx context.Context, target *ur
|
||||
}
|
||||
|
||||
func (shc *ServiceHealthChecker) newRequest(ctx context.Context, target *url.URL) (*http.Request, error) {
|
||||
pathURL, err := url.Parse(shc.config.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing health check path: %w", err)
|
||||
}
|
||||
|
||||
if pathURL.Host != "" || pathURL.Scheme != "" {
|
||||
return nil, fmt.Errorf("health check path must be a relative URL, got: %q", shc.config.Path)
|
||||
}
|
||||
|
||||
u, err := target.Parse(shc.config.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -147,6 +147,14 @@ func TestServiceHealthChecker_newRequest(t *testing.T) {
|
||||
expHostname: "backend1:80",
|
||||
expMethod: http.MethodGet,
|
||||
},
|
||||
{
|
||||
desc: "path is an ablsolute URL",
|
||||
targetURL: "http://backend1:80",
|
||||
config: dynamic.ServerHealthCheck{
|
||||
Path: "http://backend2/health?powpow=do",
|
||||
},
|
||||
expError: true,
|
||||
},
|
||||
{
|
||||
desc: "path with param",
|
||||
targetURL: "http://backend1:80",
|
||||
|
||||
@ -44,6 +44,8 @@ var hopHeaders = []string{
|
||||
forward.Upgrade,
|
||||
}
|
||||
|
||||
var userAgentHeader = http.CanonicalHeaderKey("User-Agent")
|
||||
|
||||
type forwardAuth struct {
|
||||
address string
|
||||
authResponseHeaders []string
|
||||
@ -369,6 +371,12 @@ func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowed
|
||||
RemoveConnectionHeaders(forwardReq)
|
||||
utils.RemoveHeaders(forwardReq.Header, hopHeaders...)
|
||||
|
||||
if _, ok := req.Header[userAgentHeader]; !ok {
|
||||
// If the incoming request doesn't have a User-Agent header set,
|
||||
// don't send the default Go HTTP client User-Agent for the forwarded request.
|
||||
forwardReq.Header.Set(userAgentHeader, "")
|
||||
}
|
||||
|
||||
forwardReq.Header = filterForwardRequestHeaders(forwardReq.Header, allowedHeaders)
|
||||
|
||||
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
||||
|
||||
@ -536,8 +536,7 @@ func Test_writeHeader(t *testing.T) {
|
||||
trustForwardHeader: false,
|
||||
emptyHost: true,
|
||||
expectedHeaders: map[string]string{
|
||||
"Accept": "application/json",
|
||||
"X-Forwarded-Host": "",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -610,6 +609,7 @@ func Test_writeHeader(t *testing.T) {
|
||||
"X-Forwarded-Method": "GET",
|
||||
forward.ProxyAuthenticate: "ProxyAuthenticate",
|
||||
forward.ProxyAuthorization: "ProxyAuthorization",
|
||||
"User-Agent": "",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
@ -652,6 +652,65 @@ func Test_writeHeader(t *testing.T) {
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "set empty User-Agent header if header is allowed but missing",
|
||||
headers: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
authRequestHeaders: []string{
|
||||
"X-CustomHeader",
|
||||
"Accept",
|
||||
"User-Agent",
|
||||
},
|
||||
expectedHeaders: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
"X-Forwarded-Proto": "http",
|
||||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
"X-Forwarded-Method": "GET",
|
||||
"User-Agent": "",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "ignore User-Agent header if header is not allowed and missing",
|
||||
headers: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
authRequestHeaders: []string{
|
||||
"X-CustomHeader",
|
||||
"Accept",
|
||||
},
|
||||
expectedHeaders: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
"X-Forwarded-Proto": "http",
|
||||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
"X-Forwarded-Method": "GET",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "set empty User-Agent header if header is missing",
|
||||
headers: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
expectedHeaders: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Accept": "application/json",
|
||||
"X-Forwarded-Proto": "http",
|
||||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
"X-Forwarded-Method": "GET",
|
||||
"User-Agent": "",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
@ -673,9 +732,14 @@ func Test_writeHeader(t *testing.T) {
|
||||
|
||||
expectedHeaders := test.expectedHeaders
|
||||
for key, value := range expectedHeaders {
|
||||
_, headerExists := actualHeaders[http.CanonicalHeaderKey(key)]
|
||||
|
||||
assert.True(t, headerExists, "Expected header %s not found", key)
|
||||
assert.Equal(t, value, actualHeaders.Get(key))
|
||||
|
||||
actualHeaders.Del(key)
|
||||
}
|
||||
|
||||
if test.checkForUnexpectedHeaders {
|
||||
for key := range actualHeaders {
|
||||
assert.Fail(t, "Unexpected header found", key)
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
tcpmuxer "github.com/traefik/traefik/v3/pkg/muxer/tcp"
|
||||
@ -46,7 +47,7 @@ func isPostgres(br *bufio.Reader) (bool, error) {
|
||||
func (r *Router) servePostgres(conn tcp.WriteCloser) {
|
||||
_, err := conn.Write(PostgresStartTLSReply)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
@ -55,32 +56,39 @@ func (r *Router) servePostgres(conn tcp.WriteCloser) {
|
||||
b := make([]byte, len(PostgresStartTLSMsg))
|
||||
_, err = br.Read(b)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
hello, err := clientHelloInfo(br)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if !hello.isTLS {
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// The deadline was there to prevent hanging connections while waiting for the client,
|
||||
// now that the STARTTLS message and Client Hello have been read,
|
||||
// we can remove it and leave its handling to the TCP reverse proxy eventually.
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting deadline")
|
||||
}
|
||||
|
||||
connData, err := tcpmuxer.NewConnData(hello.serverName, conn, hello.protos)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error while reading TCP connection data")
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// Contains also TCP TLS passthrough routes.
|
||||
handlerTCPTLS, _ := r.muxerTCPTLS.Match(connData)
|
||||
if handlerTCPTLS == nil {
|
||||
conn.Close()
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,15 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
)
|
||||
|
||||
const defaultBufSize = 4096
|
||||
const (
|
||||
defaultBufSize = 4096
|
||||
// Per RFC 8446 Section 5.1, the maximum TLS record payload length is 2^14 (16384) bytes.
|
||||
// A ClientHello is always a plaintext record, so any value exceeding this limit is invalid
|
||||
// and likely indicates an attack attempting to force oversized per-connection buffer allocations.
|
||||
// However, in practice the go server handshake can read up to 16384 + 2048 bytes,
|
||||
// so we need to allow for some extra bytes to avoid rejecting valid handshakes.
|
||||
maxTLSRecordLen = 16384 + 2048
|
||||
)
|
||||
|
||||
// Router is a TCP router.
|
||||
type Router struct {
|
||||
@ -126,11 +134,6 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
||||
}
|
||||
|
||||
if postgres {
|
||||
// Remove read/write deadline and delegate this to underlying TCP server.
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting deadline")
|
||||
}
|
||||
|
||||
r.servePostgres(r.GetConn(conn, getPeeked(br)))
|
||||
return
|
||||
}
|
||||
@ -141,7 +144,9 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
||||
return
|
||||
}
|
||||
|
||||
// Remove read/write deadline and delegate this to underlying TCP server (for now only handled by HTTP Server)
|
||||
// The deadline was set to avoid blocking on the initial read of the ClientHello,
|
||||
// but now that we have it, we can remove it,
|
||||
// and delegate this to underlying TCP server (for now only handled by HTTP Server).
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting deadline")
|
||||
}
|
||||
@ -409,6 +414,14 @@ func clientHelloInfo(br *bufio.Reader) (*clientHello, error) {
|
||||
|
||||
recLen := int(hdr[3])<<8 | int(hdr[4]) // ignoring version in hdr[1:3]
|
||||
|
||||
if recLen > maxTLSRecordLen {
|
||||
log.Debug().Msgf("Error while peeking client hello bytes, oversized record: %d", recLen)
|
||||
return &clientHello{
|
||||
isTLS: true,
|
||||
peeked: getPeeked(br),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if recordHeaderLen+recLen > defaultBufSize {
|
||||
br = bufio.NewReaderSize(br, recordHeaderLen+recLen)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
@ -648,6 +649,7 @@ func Test_Routing(t *testing.T) {
|
||||
_ = serverHTTPS.Serve(httpsForwarder)
|
||||
}()
|
||||
|
||||
// The HTTPS forwarder will be added as tcp.TLSHandler (to handle TLS).
|
||||
router.SetHTTPSForwarder(httpsForwarder)
|
||||
|
||||
stoppedTCP := make(chan struct{})
|
||||
@ -1082,6 +1084,118 @@ func checkHTTPSTLS12(addr string, timeout time.Duration) error {
|
||||
return checkHTTPS(addr, timeout, tls.VersionTLS12)
|
||||
}
|
||||
|
||||
// Test_clientHelloInfo_oversizedRecordLength verifies that clientHelloInfo
|
||||
// does not block or allocate excessive memory when a client sends a TLS
|
||||
// record header with a maliciously large record length (up to 0xFFFF).
|
||||
//
|
||||
// Without the fix, clientHelloInfo allocates a ~65KB bufio.Reader and blocks
|
||||
// on Peek(65540), waiting for bytes that never arrive (until readTimeout).
|
||||
// With the fix, records exceeding the TLS maximum plaintext size (16384)
|
||||
// are rejected immediately.
|
||||
func Test_clientHelloInfo_oversizedRecordLength(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
recLen uint16
|
||||
}{
|
||||
{
|
||||
desc: "max uint16 record length (0xFFFF)",
|
||||
recLen: 0xFFFF,
|
||||
},
|
||||
{
|
||||
desc: "just above TLS maximum (18433)",
|
||||
recLen: 18433,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
serverConn, clientConn := net.Pipe()
|
||||
defer serverConn.Close()
|
||||
defer clientConn.Close()
|
||||
|
||||
type result struct {
|
||||
hello *clientHello
|
||||
err error
|
||||
}
|
||||
resultCh := make(chan result, 1)
|
||||
|
||||
go func() {
|
||||
br := bufio.NewReader(serverConn)
|
||||
hello, err := clientHelloInfo(br)
|
||||
resultCh <- result{hello, err}
|
||||
}()
|
||||
|
||||
// Send a TLS record header with an oversized record length.
|
||||
// Only the 5-byte header is sent; the client then stalls.
|
||||
hdr := []byte{
|
||||
0x16, // Content Type: Handshake
|
||||
0x03, 0x03, // Version: TLS 1.2
|
||||
byte(test.recLen >> 8), // Length high byte
|
||||
byte(test.recLen & 0xFF), // Length low byte
|
||||
}
|
||||
_, err := clientConn.Write(hdr)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Without the fix, clientHelloInfo blocks on Peek(recLen+5)
|
||||
// since only 5 bytes are available. The test would time out.
|
||||
// With the fix, it returns immediately.
|
||||
select {
|
||||
case r := <-resultCh:
|
||||
require.NoError(t, r.err)
|
||||
require.NotNil(t, r.hello)
|
||||
assert.True(t, r.hello.isTLS)
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("clientHelloInfo blocked on oversized TLS record length — recLen is not capped")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test_clientHelloInfo_validRecordLength verifies that clientHelloInfo
|
||||
// still works correctly with legitimate TLS record sizes.
|
||||
func Test_clientHelloInfo_validRecordLength(t *testing.T) {
|
||||
serverConn, clientConn := net.Pipe()
|
||||
defer serverConn.Close()
|
||||
defer clientConn.Close()
|
||||
|
||||
type result struct {
|
||||
hello *clientHello
|
||||
err error
|
||||
}
|
||||
resultCh := make(chan result, 1)
|
||||
|
||||
go func() {
|
||||
br := bufio.NewReader(serverConn)
|
||||
hello, err := clientHelloInfo(br)
|
||||
resultCh <- result{hello, err}
|
||||
}()
|
||||
|
||||
// Build a TLS record header with a small (valid) record length.
|
||||
recLen := 100
|
||||
hdr := []byte{
|
||||
0x16, // Content Type: Handshake
|
||||
0x03, 0x03, // Version: TLS 1.2
|
||||
byte(recLen >> 8), // Length high byte
|
||||
byte(recLen & 0xFF), // Length low byte
|
||||
}
|
||||
payload := make([]byte, recLen)
|
||||
|
||||
_, err := clientConn.Write(append(hdr, payload...))
|
||||
require.NoError(t, err)
|
||||
clientConn.Close()
|
||||
|
||||
select {
|
||||
case r := <-resultCh:
|
||||
require.NoError(t, r.err)
|
||||
require.NotNil(t, r.hello)
|
||||
assert.True(t, r.hello.isTLS)
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("clientHelloInfo blocked on valid TLS record")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostgres(t *testing.T) {
|
||||
router, err := NewRouter()
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||
OutputType = "file"
|
||||
FileName = "traefik_changelog.md"
|
||||
|
||||
# example new bugfix v3.6.7
|
||||
# example new bugfix v3.6.8
|
||||
CurrentRef = "v3.6"
|
||||
PreviousRef = "v3.6.6"
|
||||
PreviousRef = "v3.6.7"
|
||||
BaseBranch = "v3.6"
|
||||
FutureCurrentRefName = "v3.6.7"
|
||||
FutureCurrentRefName = "v3.6.8"
|
||||
|
||||
ThresholdPreviousRef = 10000
|
||||
ThresholdCurrentRef = 10000
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user