mirror of
https://github.com/traefik/traefik
synced 2026-02-03 12:20:33 +00:00
Merge v3.6 into master
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
name: Build Web UI
|
||||
on:
|
||||
workflow_call: {}
|
||||
env:
|
||||
SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 360 # 15 days
|
||||
jobs:
|
||||
|
||||
build-webui:
|
||||
@@ -22,6 +24,12 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: webui/yarn.lock
|
||||
|
||||
- name: Setup safe-chain
|
||||
working-directory: ./webui
|
||||
run: |
|
||||
npm i -g @aikidosec/safe-chain
|
||||
safe-chain setup-ci
|
||||
|
||||
- name: Build webui
|
||||
working-directory: ./webui
|
||||
run: |
|
||||
|
||||
@@ -9,6 +9,7 @@ on:
|
||||
- 'pkg/provider/kubernetes/gateway/**'
|
||||
- 'integration/fixtures/gateway-api-conformance/**'
|
||||
- 'integration/gateway_api_conformance_test.go'
|
||||
- 'integration/integration_test.go'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.24'
|
||||
|
||||
@@ -9,6 +9,7 @@ on:
|
||||
- 'pkg/provider/kubernetes/knative/**'
|
||||
- 'integration/fixtures/knative/**'
|
||||
- 'integration/knative_conformance_test.go'
|
||||
- 'integration/integration_test.go'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.24'
|
||||
|
||||
@@ -79,6 +79,11 @@ jobs:
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: webui/yarn.lock
|
||||
|
||||
- name: Setup safe-chain
|
||||
run: |
|
||||
npm i -g @aikidosec/safe-chain
|
||||
safe-chain setup-ci
|
||||
|
||||
- name: UI unit tests
|
||||
working-directory: ./webui
|
||||
env:
|
||||
|
||||
+2
-4
@@ -239,6 +239,8 @@ linters:
|
||||
text: ' always receives '
|
||||
linters:
|
||||
- unparam
|
||||
- path: pkg/server/service/bufferpool.go
|
||||
text: 'SA6002: argument should be pointer-like to avoid allocations'
|
||||
- path: pkg/server/middleware/middlewares.go
|
||||
text: Function 'buildConstructor' has too many statements
|
||||
linters:
|
||||
@@ -314,12 +316,8 @@ linters:
|
||||
text: 'the methods of "wasmMiddlewareBuilder" use pointer receiver and non-pointer receiver.'
|
||||
linters:
|
||||
- recvcheck
|
||||
- path: pkg/server/service/bufferpool.go
|
||||
text: 'SA6002: argument should be pointer-like to avoid allocations'
|
||||
- path: pkg/proxy/httputil/bufferpool.go
|
||||
text: 'SA6002: argument should be pointer-like to avoid allocations'
|
||||
- path: pkg/udp/conn.go
|
||||
text: 'SA6002: argument should be pointer-like to avoid allocations'
|
||||
- path: integration/integration_test.go
|
||||
text: 'var (gatewayAPIConformanceRunTest|traefikVersion) is unused'
|
||||
- path: pkg/server/router/router.go
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
## [v3.6.2](https://github.com/traefik/traefik/tree/v3.6.2) (2025-11-18)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.6.1...v3.6.2)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[k8s/ingress-nginx]** Deprecate Kubernetes Ingress NGINX provider experimental flag ([#12286](https://github.com/traefik/traefik/pull/12286) by [rtribotte](https://github.com/rtribotte))
|
||||
|
||||
## [v3.6.1](https://github.com/traefik/traefik/tree/v3.6.1) (2025-11-13)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.6.0...v3.6.1)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[docker]** Auto-negotiate Docker API Version ([#12256](https://github.com/traefik/traefik/pull/12256) by [felixbuenemann](https://github.com/felixbuenemann))
|
||||
- **[server]** Fix multi-layer routing with models ([#12258](https://github.com/traefik/traefik/pull/12258) by [juliens](https://github.com/juliens))
|
||||
- **[udp]** Revert "Avoid allocations in readLoop by using sync.Pool" ([#12267](https://github.com/traefik/traefik/pull/12267) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[webui]** Fix blocked navigation on Safari ([#12231](https://github.com/traefik/traefik/pull/12231) by [gndz07](https://github.com/gndz07))
|
||||
- **[webui]** Restore remote Upgrade to Hub button web component ([#12219](https://github.com/traefik/traefik/pull/12219) by [gndz07](https://github.com/gndz07))
|
||||
|
||||
**Documentation:**
|
||||
- **[k8s]** Fix Nginx provider documentation ([#12266](https://github.com/traefik/traefik/pull/12266) by [nmengin](https://github.com/nmengin))
|
||||
- **[k8s]** Fix Gateway API version and the list of features supported ([#12254](https://github.com/traefik/traefik/pull/12254) by [nmengin](https://github.com/nmengin))
|
||||
|
||||
## [v2.11.31](https://github.com/traefik/traefik/tree/v2.11.31) (2025-11-13)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.30...v2.11.31)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[docker,docker/swarm]** Auto-negotiate Docker API version ([#12262](https://github.com/traefik/traefik/pull/12262) by [kevinpollet](https://github.com/kevinpollet))
|
||||
|
||||
## [v3.6.0](https://github.com/traefik/traefik/tree/v3.6.0) (2025-11-07)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.5.0-rc1...v3.6.0)
|
||||
|
||||
|
||||
+6
-9
@@ -1,10 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
You can join our security mailing list to be aware of the latest announcements from our security team.
|
||||
You can subscribe by sending an email to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
|
||||
Reported vulnerabilities can be found on [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=traefik).
|
||||
|
||||
## Supported Versions
|
||||
|
||||
- We usually release 3/4 new versions (e.g. 1.1.0, 1.2.0, 1.3.0) per year.
|
||||
@@ -17,10 +12,10 @@ We use [Semantic Versioning](https://semver.org/).
|
||||
|
||||
| Version | Supported |
|
||||
|-----------|--------------------|
|
||||
| `2.2.x` | :white_check_mark: |
|
||||
| `< 2.2.x` | :x: |
|
||||
| `1.7.x` | :white_check_mark: |
|
||||
| `< 1.7.x` | :x: |
|
||||
| `3.6.x` | :white_check_mark: |
|
||||
| `< 3.6.x` | :x: |
|
||||
| `2.11.x` | :white_check_mark: |
|
||||
| `< 2.11.x` | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -28,3 +23,5 @@ We want to keep Traefik safe for everyone.
|
||||
If you've discovered a security vulnerability in Traefik,
|
||||
we appreciate your help in disclosing it to us in a responsible manner,
|
||||
by creating a [security advisory](https://github.com/traefik/traefik/security/advisories).
|
||||
|
||||
Reported vulnerabilities can be found on [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=traefik).
|
||||
|
||||
+17
-4
@@ -114,9 +114,7 @@ func runCmd(staticConfiguration *static.Configuration) error {
|
||||
log.Debug().RawJSON("staticConfiguration", []byte(redactedStaticConfiguration)).Msg("Static configuration loaded [json]")
|
||||
}
|
||||
|
||||
if staticConfiguration.Global.CheckNewVersion {
|
||||
checkNewVersion()
|
||||
}
|
||||
checkNewVersion(staticConfiguration)
|
||||
|
||||
stats(staticConfiguration)
|
||||
|
||||
@@ -614,13 +612,28 @@ func setupTracing(ctx context.Context, conf *static.Tracing) (*tracing.Tracer, i
|
||||
return tracer, closer
|
||||
}
|
||||
|
||||
func checkNewVersion() {
|
||||
func checkNewVersion(staticConfiguration *static.Configuration) {
|
||||
logger := log.With().Logger()
|
||||
|
||||
if staticConfiguration.Global.CheckNewVersion {
|
||||
logger.Info().Msg(`Version check is enabled.`)
|
||||
logger.Info().Msg(`Traefik checks for new releases to notify you if your version is out of date.`)
|
||||
logger.Info().Msg(`It also collects usage data during this process.`)
|
||||
logger.Info().Msg(`Check the documentation to get more info: https://doc.traefik.io/traefik/contributing/data-collection/`)
|
||||
|
||||
ticker := time.Tick(24 * time.Hour)
|
||||
safe.Go(func() {
|
||||
for time.Sleep(10 * time.Minute); ; <-ticker {
|
||||
version.CheckNewVersion()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
logger.Info().Msg(`
|
||||
Version check is disabled.
|
||||
You will not be notified if a new version is available.
|
||||
More details: https://doc.traefik.io/traefik/contributing/data-collection/
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
func stats(staticConfiguration *static.Configuration) {
|
||||
|
||||
@@ -1,17 +1,72 @@
|
||||
---
|
||||
title: "Traefik Data Collection Documentation"
|
||||
description: "To learn more about how Traefik is being used and improve it, we collect anonymous usage statistics from running instances. Read the technical documentation."
|
||||
description: "Learn what data Traefik shares, how it is used, and how you can control it. This documentation explains both version check and anonymous usage statistics data. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Data Collection
|
||||
|
||||
Understanding How Traefik is Being Used
|
||||
Understanding the data Traefik shares and how it is used
|
||||
{: .subtitle }
|
||||
|
||||
## Configuration Example
|
||||
## Introduction
|
||||
|
||||
Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways.
|
||||
For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us, so we can benefit from your experience and use cases.
|
||||
Protecting user privacy is essential to Traefik Labs, and we design every data-sharing mechanism with transparency and minimalism in mind.
|
||||
This page describes the two types of data exchanged by Traefik and how to configure them.
|
||||
|
||||
For more details on how your data is handled, please refer to our [Privacy and Cookie Policy](https://traefik.io/legal/privacy-and-cookie-policy).
|
||||
|
||||
## Configuration Overview
|
||||
|
||||
Traefik provides two independent mechanisms:
|
||||
|
||||
- `checkNewVersion`, enabled by default. You may disable it at any time.
|
||||
- `sendAnonymousUsage`, which requires explicit opt‑in.
|
||||
|
||||
Examples below show how to activate or deactivate both of them.
|
||||
|
||||
```yaml tab="YAML"
|
||||
global:
|
||||
checkNewVersion: true # set to false to disable
|
||||
sendAnonymousUsage: false # set to true to enable
|
||||
```
|
||||
|
||||
```toml tab="TOML"
|
||||
[global]
|
||||
checkNewVersion = true # set to false to disable
|
||||
sendAnonymousUsage = false # set to true to enable
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--global.checkNewVersion=true # set to false to disable
|
||||
--global.sendAnonymousUsage=false # set to true to enable
|
||||
```
|
||||
|
||||
A log message at startup clearly indicates whether each of those options are enabled or disabled.
|
||||
|
||||
## Version Check (`checkNewVersion`) – Opt-out
|
||||
|
||||
Traefik periodically contacts `update.traefik.io` to determine whether a newer version is available.
|
||||
When this request is made, Traefik shares the **running version** and the **public IP** of the instance.
|
||||
The IP is used to build global usage statistics and does not influence the version comparison.
|
||||
|
||||
This mechanism helps you stay informed about updates and provides TraefikLabs with a broad view of which versions are deployed in the wild.
|
||||
|
||||
The collected IP addresses are also used for marketing purposes, specifically to detect companies running Traefik and offer them adapted support contracts, enterprise features, and tailored services.
|
||||
|
||||
If you want to explore the implementation, you can read the version check source code: [version.go](https://github.com/traefik/traefik/blob/master/pkg/version/version.go)
|
||||
|
||||
## Anonymous Usage Data (`sendAnonymousUsage`) – Opt‑in
|
||||
|
||||
Traefik can also collect anonymous usage statistics once per day, starting 10 minutes after it starts running.
|
||||
These statistics include:
|
||||
|
||||
- the Traefik version,
|
||||
- a hash of the configuration,
|
||||
- an anonymized version of the static configuration (all sensitive fields removed: tokens, passwords, URLs, IP addresses, domains, emails, etc.).
|
||||
|
||||
This feature comes from this [public proposal](https://github.com/traefik/traefik/issues/2369).
|
||||
|
||||
This information helps TraefikLabs understand how Traefik is used in general and prioritize features and provider support accordingly. Dynamic configuration (routers and services) is never collected.
|
||||
|
||||
!!! example "Enabling Data Collection"
|
||||
|
||||
@@ -32,21 +87,6 @@ For this very reason, the sendAnonymousUsage option is mandatory: we want you to
|
||||
--global.sendAnonymousUsage
|
||||
```
|
||||
|
||||
## Collected Data
|
||||
|
||||
This feature comes from this [public proposal](https://github.com/traefik/traefik/issues/2369).
|
||||
|
||||
In order to help us learn more about how Traefik is being used and improve it, we collect anonymous usage statistics from running instances.
|
||||
Those data help us prioritize our developments and focus on what's important for our users (for example, which provider is popular, and which is not).
|
||||
|
||||
### What's collected / when ?
|
||||
|
||||
Once a day (the first call begins 10 minutes after the start of Traefik), we collect:
|
||||
|
||||
- the Traefik version number
|
||||
- a hash of the configuration
|
||||
- an **anonymized version** of the static configuration (token, username, password, URL, IP, domain, email, etc., are removed).
|
||||
|
||||
!!! info
|
||||
|
||||
- We do not collect the dynamic configuration information (routers & services).
|
||||
@@ -93,8 +133,9 @@ providers:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
## The Code for Data Collection
|
||||
### The Code for Anonymous Usage Collection
|
||||
|
||||
If you want to dig into more details, here is the source code of the collecting system: [collector.go](https://github.com/traefik/traefik/blob/master/pkg/collector/collector.go)
|
||||
If you want to explore the implementation, you can read the collector source code:
|
||||
[collector.go](https://github.com/traefik/traefik/blob/master/pkg/collector/collector.go)
|
||||
|
||||
By default, we anonymize all configuration fields, except fields tagged with `export=true`.
|
||||
Traefik anonymizes all configuration fields by default, except those explicitly marked with `export=true`.
|
||||
|
||||
@@ -525,3 +525,32 @@ To use the new `leasttime` load-balancer algorithm with the Kubernetes CRD provi
|
||||
```shell
|
||||
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
|
||||
```
|
||||
|
||||
## v3.6.2
|
||||
|
||||
### Ingress NGINX Provider
|
||||
|
||||
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:**
|
||||
|
||||
1. Remove the `kubernetesIngressNGINX` option from the experimental section
|
||||
2. Configure the provider using the [kubernetesIngressNGINX Provider documentation](../reference/install-configuration/providers/kubernetes/kubernetes-ingress-nginx.md)
|
||||
|
||||
@@ -21,7 +21,7 @@ For more details, check out the conformance [report](https://github.com/kubernet
|
||||
!!! info "Helm Chart"
|
||||
|
||||
When using the Traefik [Helm Chart](../getting-started/install-traefik.md#use-the-helm-chart), the CRDs (Custom Resource Definitions) and RBAC (Role-Based Access Control) are automatically managed for you.
|
||||
The only remaining task is to enable the `kubernetesGateway` in the chart [values](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml#L130).
|
||||
The only remaining task is to enable the `kubernetesGateway` in the chart [values](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml#L323).
|
||||
|
||||
1. Install/update the Kubernetes Gateway API CRDs.
|
||||
|
||||
|
||||
+2
-2
@@ -10,14 +10,14 @@ specification from the Kubernetes Special Interest Groups (SIGs).
|
||||
|
||||
This provider supports Standard version [v1.4.0](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.4.0) of the Gateway API specification.
|
||||
|
||||
It fully supports all HTTP core and some extended features, as well as the `TCPRoute` and `TLSRoute` resources from the [Experimental channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels).
|
||||
It fully supports all `HTTPRoute` core and some extended features, like `BackendTLSPolicy`, and `GRPCRoute` resources from the [Standard channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels), as well as `TCPRoute`, and `TLSRoute` resources from the [Experimental channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels).
|
||||
|
||||
For more details, check out the conformance [report](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports/v1.4.0/traefik-traefik).
|
||||
|
||||
!!! info "Using The Helm Chart"
|
||||
|
||||
When using the Traefik [Helm Chart](../../../../getting-started/install-traefik.md#use-the-helm-chart), the CRDs (Custom Resource Definitions) and RBAC (Role-Based Access Control) are automatically managed for you.
|
||||
The only remaining task is to enable the `kubernetesGateway` in the chart [values](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml#L130).
|
||||
The only remaining task is to enable the `kubernetesGateway` in the chart [values](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml#L323).
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
+151
-35
@@ -5,65 +5,181 @@ description: "Understand the requirements, routing configuration, and how to set
|
||||
|
||||
# Traefik & Ingresses with NGINX Annotations
|
||||
|
||||
The experimental Traefik Kubernetes Ingress NGINX provider is a Kubernetes Ingress controller; i.e,
|
||||
it manages access to cluster services by supporting the [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) specification.
|
||||
It also supports some of the [ingress-nginx](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/) annotations on ingresses to customize their behavior.
|
||||
This provider is a Kubernetes Ingress controller that manages access to cluster services by supporting the [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) specification.
|
||||
It also supports many of the [ingress-nginx](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/) annotations on Ingresses, enabling teams to migrate from NGINX Ingress Controller to Traefik with minimal configuration changes.
|
||||
|
||||
!!! warning "Ingress Discovery"
|
||||
!!! warning "NGINX Ingress Controller Retirement"
|
||||
|
||||
The Kubernetes Ingress NGINX provider is discovering by default all Ingresses in the cluster,
|
||||
which may lead to duplicated routers if you are also using the Kubernetes Ingress provider.
|
||||
We recommend to use IngressClass for the Ingresses you want to be handled by this provider,
|
||||
or to use the `watchNamespace` or `watchNamespaceSelector` options to limit the discovery of Ingresses to a specific namespace or set of namespaces.
|
||||
The Kubernetes NGINX Ingress Controller project has announced its retirement in **March 2026** and will no longer receive updates or security patches.
|
||||
Traefik provides a migration path by supporting NGINX annotations, allowing you to transition your workloads without rewriting all your Ingress configurations.
|
||||
|
||||
For more information about the NGINX Ingress Controller retirement, see the [official Kubernetes blog announcement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement).
|
||||
|
||||
## Ingress Discovery
|
||||
|
||||
This provider discovers all Ingresses in the cluster by default, which may lead to duplicated routers if you are also using the standard Kubernetes Ingress provider.
|
||||
|
||||
**Best Practices:**
|
||||
|
||||
- Use IngressClass to specify which Ingresses should be handled by this provider
|
||||
- Configure `watchNamespace` to limit discovery to specific namespaces
|
||||
- Use `watchNamespaceSelector` to target Ingresses based on namespace labels
|
||||
|
||||
## Configuration Example
|
||||
|
||||
As this provider is an experimental feature, it needs to be enabled in the experimental and in the provider sections of the configuration.
|
||||
You can enable the Kubernetes Ingress NGINX provider as detailed below:
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
experimental:
|
||||
kubernetesIngressNGINX: true
|
||||
|
||||
providers:
|
||||
kubernetesIngressNGINX: {}
|
||||
kubernetesIngressNGINX:
|
||||
endpoint: "https://kubernetes.default.svc"
|
||||
token: "mytoken"
|
||||
certAuthFilePath: "/path/to/ca.crt"
|
||||
throttleDuration: "2s"
|
||||
|
||||
# Namespace discovery
|
||||
watchNamespace: "default"
|
||||
# OR use namespace selector (mutually exclusive with watchNamespace)
|
||||
# watchNamespaceSelector: "environment=production"
|
||||
|
||||
# IngressClass configuration
|
||||
ingressClass: "nginx"
|
||||
controllerClass: "k8s.io/ingress-nginx"
|
||||
watchIngressWithoutClass: false
|
||||
ingressClassByName: false
|
||||
|
||||
# Status updates
|
||||
publishService: "kube-system/traefik"
|
||||
publishStatusAddress: "203.0.113.42"
|
||||
|
||||
# Default backend
|
||||
defaultBackendService: "default/default-backend"
|
||||
|
||||
# Security
|
||||
disableSvcExternalName: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[experimental.kubernetesIngressNGINX]
|
||||
|
||||
[providers.kubernetesIngressNGINX]
|
||||
endpoint = "https://kubernetes.default.svc"
|
||||
token = "mytoken"
|
||||
certAuthFilePath = "/path/to/ca.crt"
|
||||
throttleDuration = "2s"
|
||||
|
||||
# Namespace discovery
|
||||
watchNamespace = "default"
|
||||
# OR use namespace selector (mutually exclusive with watchNamespace)
|
||||
# watchNamespaceSelector = "environment=production"
|
||||
|
||||
# IngressClass configuration
|
||||
ingressClass = "nginx"
|
||||
controllerClass = "k8s.io/ingress-nginx"
|
||||
watchIngressWithoutClass = false
|
||||
ingressClassByName = false
|
||||
|
||||
# Status updates
|
||||
publishService = "kube-system/traefik"
|
||||
publishStatusAddress = "203.0.113.42"
|
||||
|
||||
# Default backend
|
||||
defaultBackendService = "default/default-backend"
|
||||
|
||||
# Security
|
||||
disableSvcExternalName = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--experimental.kubernetesingressnginx=true
|
||||
--providers.kubernetesingressnginx=true
|
||||
--providers.kubernetesingressnginx.endpoint=https://kubernetes.default.svc
|
||||
--providers.kubernetesingressnginx.token=mytoken
|
||||
--providers.kubernetesingressnginx.certauthfilepath=/path/to/ca.crt
|
||||
--providers.kubernetesingressnginx.throttleduration=2s
|
||||
--providers.kubernetesingressnginx.watchnamespace=default
|
||||
--providers.kubernetesingressnginx.ingressclass=nginx
|
||||
--providers.kubernetesingressnginx.controllerclass=k8s.io/ingress-nginx
|
||||
--providers.kubernetesingressnginx.watchingresswithoutclass=false
|
||||
--providers.kubernetesingressnginx.ingressclassbyname=false
|
||||
--providers.kubernetesingressnginx.publishservice=kube-system/traefik
|
||||
--providers.kubernetesingressnginx.publishstatusaddress=203.0.113.42
|
||||
--providers.kubernetesingressnginx.defaultbackendservice=default/default-backend
|
||||
--providers.kubernetesingressnginx.disablesvcexternalname=false
|
||||
```
|
||||
|
||||
The provider then watches for incoming ingresses events, such as the example below,
|
||||
and derives the corresponding dynamic configuration from it,
|
||||
which in turn creates the resulting routers, services, handlers, etc.
|
||||
```yaml tab="Helm Chart Values"
|
||||
providers:
|
||||
kubernetesIngressNginx:
|
||||
# -- Enable Kubernetes Ingress NGINX provider
|
||||
enabled: true
|
||||
|
||||
# -- Kubernetes server endpoint (required for external cluster client)
|
||||
endpoint: "https://kubernetes.default.svc"
|
||||
|
||||
# -- Kubernetes bearer token (not needed for in-cluster client)
|
||||
token: "mytoken"
|
||||
|
||||
# -- Kubernetes certificate authority file path (not needed for in-cluster client)
|
||||
certAuthFilePath: "/path/to/ca.crt"
|
||||
|
||||
# -- Ingress refresh throttle duration
|
||||
throttleDuration: "2s"
|
||||
|
||||
# Namespace discovery
|
||||
# -- Namespace the controller watches for updates to Kubernetes objects
|
||||
# When using rbac.namespaced, it will watch helm release namespace and namespaces listed in this array
|
||||
namespaces:
|
||||
- default
|
||||
# OR use namespace selector (mutually exclusive with namespaces)
|
||||
# namespaceSelector: "environment=production"
|
||||
|
||||
# IngressClass configuration
|
||||
# -- Name of the ingress class this controller satisfies
|
||||
ingressClass: "nginx"
|
||||
# -- Ingress Class Controller value this controller satisfies
|
||||
controllerClass: "k8s.io/ingress-nginx"
|
||||
# -- Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified
|
||||
watchIngressWithoutClass: false
|
||||
# -- Define if Ingress Controller should watch for Ingress Class by Name together with Controller Class
|
||||
ingressClassByName: false
|
||||
|
||||
# Status updates
|
||||
# -- Service fronting the Ingress controller
|
||||
publishService:
|
||||
enabled: true
|
||||
pathOverride: "kube-system/traefik"
|
||||
# -- Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects
|
||||
publishStatusAddress: "203.0.113.42"
|
||||
|
||||
# Default backend
|
||||
# -- Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form 'namespace/name'
|
||||
defaultBackendService: "default/default-backend"
|
||||
|
||||
# Security
|
||||
# -- Disable support for Services of type ExternalName
|
||||
disableSvcExternalName: false
|
||||
```
|
||||
|
||||
This provider watches for incoming Ingress events and automatically translates NGINX annotations into Traefik's dynamic configuration, creating the corresponding routers, services, middlewares, and other components needed to route traffic to your cluster services.
|
||||
|
||||
## Configuration Options
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| <a id="opt-providers-providersThrottleDuration" href="#opt-providers-providersThrottleDuration" title="#opt-providers-providersThrottleDuration">`providers.providersThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-endpoint" href="#opt-providers-kubernetesIngressNGINX-endpoint" title="#opt-providers-kubernetesIngressNGINX-endpoint">`providers.kubernetesIngressNGINX.endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-token" href="#opt-providers-kubernetesIngressNGINX-token" title="#opt-providers-kubernetesIngressNGINX-token">`providers.kubernetesIngressNGINX.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-certAuthFilePath" href="#opt-providers-kubernetesIngressNGINX-certAuthFilePath" title="#opt-providers-kubernetesIngressNGINX-certAuthFilePath">`providers.kubernetesIngressNGINX.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-throttleDuration" href="#opt-providers-kubernetesIngressNGINX-throttleDuration" title="#opt-providers-kubernetesIngressNGINX-throttleDuration">`providers.kubernetesIngressNGINX.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-kubernetesIngressNGINX-watchNamespace" href="#opt-providers-kubernetesIngressNGINX-watchNamespace" title="#opt-providers-kubernetesIngressNGINX-watchNamespace">`providers.kubernetesIngressNGINX.watchNamespace`</a> | Namespace the controller watches for updates to Kubernetes objects. All namespaces are watched if this parameter is left empty. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-watchNamespaceSelector" href="#opt-providers-kubernetesIngressNGINX-watchNamespaceSelector" title="#opt-providers-kubernetesIngressNGINX-watchNamespaceSelector">`providers.kubernetesIngressNGINX.watchNamespaceSelector`</a> | Selector selects namespaces the controller watches for updates to Kubernetes objects. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-ingressClass" href="#opt-providers-kubernetesIngressNGINX-ingressClass" title="#opt-providers-kubernetesIngressNGINX-ingressClass">`providers.kubernetesIngressNGINX.ingressClass`</a> | Name of the ingress class this controller satisfies. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-controllerClass" href="#opt-providers-kubernetesIngressNGINX-controllerClass" title="#opt-providers-kubernetesIngressNGINX-controllerClass">`providers.kubernetesIngressNGINX.controllerClass`</a> | Ingress Class Controller value this controller satisfies. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass" href="#opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass" title="#opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass">`providers.kubernetesIngressNGINX.watchIngressWithoutClass`</a> | Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified. | false | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-ingressClassByName" href="#opt-providers-kubernetesIngressNGINX-ingressClassByName" title="#opt-providers-kubernetesIngressNGINX-ingressClassByName">`providers.kubernetesIngressNGINX.ingressClassByName`</a> | Define if Ingress Controller should watch for Ingress Class by Name together with Controller Class. | false | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-publishService" href="#opt-providers-kubernetesIngressNGINX-publishService" title="#opt-providers-kubernetesIngressNGINX-publishService">`providers.kubernetesIngressNGINX.publishService`</a> | Service fronting the Ingress controller. Takes the form namespace/name. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-publishStatusAddress" href="#opt-providers-kubernetesIngressNGINX-publishStatusAddress" title="#opt-providers-kubernetesIngressNGINX-publishStatusAddress">`providers.kubernetesIngressNGINX.publishStatusAddress`</a> | Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects this controller satisfies. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-defaultBackendService" href="#opt-providers-kubernetesIngressNGINX-defaultBackendService" title="#opt-providers-kubernetesIngressNGINX-defaultBackendService">`providers.kubernetesIngressNGINX.defaultBackendService`</a> | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form 'namespace/name'. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-disableSvcExternalName" href="#opt-providers-kubernetesIngressNGINX-disableSvcExternalName" title="#opt-providers-kubernetesIngressNGINX-disableSvcExternalName">`providers.kubernetesIngressNGINX.disableSvcExternalName`</a> | Disable support for Services of type ExternalName. | false | No |
|
||||
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------|:--------|:---------|
|
||||
| <a id="opt-providers-providers-ThrottleDuration" href="#opt-providers-providers-ThrottleDuration" title="#opt-providers-providers-ThrottleDuration">`providers.providers`<br/>`ThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-endpoint" href="#opt-providers-kubernetesIngressNGINX-endpoint" title="#opt-providers-kubernetesIngressNGINX-endpoint">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-token" href="#opt-providers-kubernetesIngressNGINX-token" title="#opt-providers-kubernetesIngressNGINX-token">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-certAuthFilePath" href="#opt-providers-kubernetesIngressNGINX-certAuthFilePath" title="#opt-providers-kubernetesIngressNGINX-certAuthFilePath">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-throttleDuration" href="#opt-providers-kubernetesIngressNGINX-throttleDuration" title="#opt-providers-kubernetesIngressNGINX-throttleDuration">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`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-kubernetesIngressNGINX-watchNamespace" href="#opt-providers-kubernetesIngressNGINX-watchNamespace" title="#opt-providers-kubernetesIngressNGINX-watchNamespace">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`watchNamespace`</a> | Namespace the controller watches for updates to Kubernetes objects. All namespaces are watched if this parameter is left empty. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-watchNamespaceSelector" href="#opt-providers-kubernetesIngressNGINX-watchNamespaceSelector" title="#opt-providers-kubernetesIngressNGINX-watchNamespaceSelector">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`watchNamespaceSelector`</a> | Selector selects namespaces the controller watches for updates to Kubernetes objects. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-ingressClass" href="#opt-providers-kubernetesIngressNGINX-ingressClass" title="#opt-providers-kubernetesIngressNGINX-ingressClass">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`ingressClass`</a> | Name of the ingress class this controller satisfies. | "nginx" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-controllerClass" href="#opt-providers-kubernetesIngressNGINX-controllerClass" title="#opt-providers-kubernetesIngressNGINX-controllerClass">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`controllerClass`</a> | Ingress Class Controller value this controller satisfies. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass" href="#opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass" title="#opt-providers-kubernetesIngressNGINX-watchIngressWithoutClass">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`watchIngressWithoutClass`</a> | Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified. | false | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-ingressClassByName" href="#opt-providers-kubernetesIngressNGINX-ingressClassByName" title="#opt-providers-kubernetesIngressNGINX-ingressClassByName">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`ingressClassByName`</a> | Define if Ingress Controller should watch for Ingress Class by Name together with Controller Class. | false | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-publishService" href="#opt-providers-kubernetesIngressNGINX-publishService" title="#opt-providers-kubernetesIngressNGINX-publishService">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`publishService`</a> | Service fronting the Ingress controller. Takes the form `namespace/name`. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-publishStatusAddress" href="#opt-providers-kubernetesIngressNGINX-publishStatusAddress" title="#opt-providers-kubernetesIngressNGINX-publishStatusAddress">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`publishStatusAddress`</a> | Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects this controller satisfies. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-defaultBackendService" href="#opt-providers-kubernetesIngressNGINX-defaultBackendService" title="#opt-providers-kubernetesIngressNGINX-defaultBackendService">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`defaultBackendService`</a> | Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form 'namespace/name'. | "" | No |
|
||||
| <a id="opt-providers-kubernetesIngressNGINX-disableSvcExternalName" href="#opt-providers-kubernetesIngressNGINX-disableSvcExternalName" title="#opt-providers-kubernetesIngressNGINX-disableSvcExternalName">`providers.`<br/>`kubernetesIngressNGINX.`<br/>`disableSvcExternalName`</a> | Disable support for Services of type ExternalName. | false | No |
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
|
||||
@@ -8,11 +8,12 @@ description: "The Kubernetes Gateway API can be used as a provider for routing a
|
||||
When using the Kubernetes Gateway API provider, Traefik leverages the Gateway API Custom Resource Definitions (CRDs) to obtain its routing configuration.
|
||||
For detailed information on the Gateway API concepts and resources, refer to the official [documentation](https://gateway-api.sigs.k8s.io/).
|
||||
|
||||
The Kubernetes Gateway API provider supports version [v1.2.1](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.1) of the specification.
|
||||
The Kubernetes Gateway API provider supports version [v1.4.0](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.4.0) of the specification.
|
||||
|
||||
It fully supports all `HTTPRoute` core and some extended features, like `GRPCRoute`, as well as the `TCPRoute` and `TLSRoute` resources from the [Experimental channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels).
|
||||
It fully supports all `HTTPRoute` core and some extended features, like `BackendTLSPolicy`, and `GRPCRoute` resources from the [Standard channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels), as well as `TCPRoute`, and `TLSRoute` resources from the [Experimental channel](https://gateway-api.sigs.k8s.io/concepts/versioning/?h=#release-channels).
|
||||
|
||||
For more details, check out the conformance [report](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports/v1.4.0/traefik-traefik).
|
||||
|
||||
For more details, check out the conformance [report](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports/v1.2.1/traefik-traefik).
|
||||
|
||||
## Deploying a Gateway
|
||||
|
||||
|
||||
@@ -5,21 +5,29 @@ description: "Understand the routing configuration for the Kubernetes Ingress NG
|
||||
|
||||
# Traefik & Ingresses with NGINX Annotations
|
||||
|
||||
The experimental Kubernetes Controller for Ingresses with NGINX annotations.
|
||||
Enable seamless migration from NGINX Ingress Controller to Traefik with NGINX annotation compatibility.
|
||||
{: .subtitle }
|
||||
|
||||
!!! warning "Ingress Discovery"
|
||||
!!! warning "NGINX Ingress Controller Retirement"
|
||||
|
||||
The Kubernetes Ingress NGINX provider is discovering by default all Ingresses in the cluster,
|
||||
which may lead to duplicated routers if you are also using the Kubernetes Ingress provider.
|
||||
We recommend to use IngressClass for the Ingresses you want to be handled by this provider,
|
||||
or to use the `watchNamespace` or `watchNamespaceSelector` options to limit the discovery of Ingresses to a specific namespace or set of namespaces.
|
||||
The Kubernetes NGINX Ingress Controller project has announced its retirement in **March 2026** and will no longer receive updates or security patches.
|
||||
Traefik provides a migration path by supporting NGINX annotations, allowing you to transition your workloads without rewriting all your Ingress configurations.
|
||||
|
||||
For more information about the NGINX Ingress Controller retirement, see the [official Kubernetes blog announcement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement).
|
||||
|
||||
## Ingress Discovery
|
||||
|
||||
This provider discovers all Ingresses in the cluster by default, which may lead to duplicated routers if you are also using the standard Kubernetes Ingress provider.
|
||||
|
||||
**Best Practices:**
|
||||
|
||||
- Use IngressClass to specify which Ingresses should be handled by this provider
|
||||
- Configure `watchNamespace` to limit discovery to specific namespaces
|
||||
- Use `watchNamespaceSelector` to target Ingresses based on namespace labels
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
The Kubernetes Ingress NGINX provider watches for incoming ingresses events, such as the example below,
|
||||
and derives the corresponding dynamic configuration from it,
|
||||
which in turn will create the resulting routers, services, handlers, etc.
|
||||
This provider watches for incoming Ingress events and automatically translates NGINX annotations into Traefik's dynamic configuration, creating the corresponding routers, services, middlewares, and other components needed to handle your traffic.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
@@ -239,32 +247,13 @@ which in turn will create the resulting routers, services, handlers, etc.
|
||||
|
||||
## Annotations Support
|
||||
|
||||
This section lists all known NGINX Ingress annotations, split between those currently implemented (with limitations if any) and those not implemented.
|
||||
Limitations or behavioral differences are indicated where relevant.
|
||||
This section lists all known NGINX Ingress annotations.
|
||||
The following annotations are organized by category for easier navigation.
|
||||
|
||||
!!! warning "Global configuration"
|
||||
|
||||
Traefik does not expose all global configuration options to control default behaviors for ingresses.
|
||||
|
||||
Some behaviors that are globally configurable in NGINX (such as default SSL redirect, rate limiting, or affinity) are currently not supported and cannot be overridden per-ingress as in NGINX.
|
||||
|
||||
### Caveats and Key Behavioral Differences
|
||||
|
||||
- **Authentication**: Forward auth behaves differently and session caching is not supported. NGINX supports sub-request based auth, while Traefik forwards the original request.
|
||||
- **Session Affinity**: Only persistent mode is supported.
|
||||
- **Leader Election**: Not supported; no cluster mode with leader election.
|
||||
- **Default Backend**: Only `defaultBackend` in Ingress spec is supported; the annotation is ignored.
|
||||
- **Load Balancing**: Only round_robin is supported; EWMA and IP hash are not supported.
|
||||
- **CORS**: NGINX responds with all configured headers unconditionally; Traefik handles headers differently between pre-flight and regular requests.
|
||||
- **TLS/Backend Protocols**: AUTO_HTTP, FCGI and some TLS options are not supported in Traefik.
|
||||
- **Path Handling**: Traefik preserves trailing slashes by default; NGINX removes them unless configured otherwise.
|
||||
|
||||
### Supported NGINX Annotations
|
||||
### Authentication
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity" href="#opt-nginx-ingress-kubernetes-ioaffinity" title="#opt-nginx-ingress-kubernetes-ioaffinity">`nginx.ingress.kubernetes.io/affinity`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity-mode" href="#opt-nginx-ingress-kubernetes-ioaffinity-mode" title="#opt-nginx-ingress-kubernetes-ioaffinity-mode">`nginx.ingress.kubernetes.io/affinity-mode`</a> | Only persistent mode supported; balanced/canary not supported. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-type" href="#opt-nginx-ingress-kubernetes-ioauth-type" title="#opt-nginx-ingress-kubernetes-ioauth-type">`nginx.ingress.kubernetes.io/auth-type`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-secret" href="#opt-nginx-ingress-kubernetes-ioauth-secret" title="#opt-nginx-ingress-kubernetes-ioauth-secret">`nginx.ingress.kubernetes.io/auth-secret`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-secret-type" href="#opt-nginx-ingress-kubernetes-ioauth-secret-type" title="#opt-nginx-ingress-kubernetes-ioauth-secret-type">`nginx.ingress.kubernetes.io/auth-secret-type`</a> | |
|
||||
@@ -272,29 +261,69 @@ Limitations or behavioral differences are indicated where relevant.
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-url" href="#opt-nginx-ingress-kubernetes-ioauth-url" title="#opt-nginx-ingress-kubernetes-ioauth-url">`nginx.ingress.kubernetes.io/auth-url`</a> | Only URL and response headers copy supported. Forward auth behaves differently than NGINX. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-method" href="#opt-nginx-ingress-kubernetes-ioauth-method" title="#opt-nginx-ingress-kubernetes-ioauth-method">`nginx.ingress.kubernetes.io/auth-method`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-response-headers" href="#opt-nginx-ingress-kubernetes-ioauth-response-headers" title="#opt-nginx-ingress-kubernetes-ioauth-response-headers">`nginx.ingress.kubernetes.io/auth-response-headers`</a> | |
|
||||
|
||||
### SSL/TLS
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-redirect" href="#opt-nginx-ingress-kubernetes-iossl-redirect" title="#opt-nginx-ingress-kubernetes-iossl-redirect">`nginx.ingress.kubernetes.io/ssl-redirect`</a> | Cannot opt-out per route if enabled globally. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioforce-ssl-redirect" href="#opt-nginx-ingress-kubernetes-ioforce-ssl-redirect" title="#opt-nginx-ingress-kubernetes-ioforce-ssl-redirect">`nginx.ingress.kubernetes.io/force-ssl-redirect`</a> | Cannot opt-out per route if enabled globally. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-passthrough" href="#opt-nginx-ingress-kubernetes-iossl-passthrough" title="#opt-nginx-ingress-kubernetes-iossl-passthrough">`nginx.ingress.kubernetes.io/ssl-passthrough`</a> | Some differences in SNI/default backend handling. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iouse-regex" href="#opt-nginx-ingress-kubernetes-iouse-regex" title="#opt-nginx-ingress-kubernetes-iouse-regex">`nginx.ingress.kubernetes.io/use-regex`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name">`nginx.ingress.kubernetes.io/proxy-ssl-server-name`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-name" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-name" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-name">`nginx.ingress.kubernetes.io/proxy-ssl-name`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-verify" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify">`nginx.ingress.kubernetes.io/proxy-ssl-verify`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-secret" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-secret" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-secret">`nginx.ingress.kubernetes.io/proxy-ssl-secret`</a> | |
|
||||
|
||||
### Session Affinity
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity" href="#opt-nginx-ingress-kubernetes-ioaffinity" title="#opt-nginx-ingress-kubernetes-ioaffinity">`nginx.ingress.kubernetes.io/affinity`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity-mode" href="#opt-nginx-ingress-kubernetes-ioaffinity-mode" title="#opt-nginx-ingress-kubernetes-ioaffinity-mode">`nginx.ingress.kubernetes.io/affinity-mode`</a> | Only persistent mode supported; balanced/canary not supported. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-name" href="#opt-nginx-ingress-kubernetes-iosession-cookie-name" title="#opt-nginx-ingress-kubernetes-iosession-cookie-name">`nginx.ingress.kubernetes.io/session-cookie-name`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-path" href="#opt-nginx-ingress-kubernetes-iosession-cookie-path" title="#opt-nginx-ingress-kubernetes-iosession-cookie-path">`nginx.ingress.kubernetes.io/session-cookie-path`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-domain" href="#opt-nginx-ingress-kubernetes-iosession-cookie-domain" title="#opt-nginx-ingress-kubernetes-iosession-cookie-domain">`nginx.ingress.kubernetes.io/session-cookie-domain`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-samesite" href="#opt-nginx-ingress-kubernetes-iosession-cookie-samesite" title="#opt-nginx-ingress-kubernetes-iosession-cookie-samesite">`nginx.ingress.kubernetes.io/session-cookie-samesite`</a> | |
|
||||
|
||||
### Load Balancing & Backend
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioload-balance" href="#opt-nginx-ingress-kubernetes-ioload-balance" title="#opt-nginx-ingress-kubernetes-ioload-balance">`nginx.ingress.kubernetes.io/load-balance`</a> | Only round_robin supported; ewma and IP hash not supported. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iobackend-protocol" href="#opt-nginx-ingress-kubernetes-iobackend-protocol" title="#opt-nginx-ingress-kubernetes-iobackend-protocol">`nginx.ingress.kubernetes.io/backend-protocol`</a> | FCGI and AUTO_HTTP not supported. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioservice-upstream" href="#opt-nginx-ingress-kubernetes-ioservice-upstream" title="#opt-nginx-ingress-kubernetes-ioservice-upstream">`nginx.ingress.kubernetes.io/service-upstream`</a> | |
|
||||
|
||||
### CORS
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-cors" href="#opt-nginx-ingress-kubernetes-ioenable-cors" title="#opt-nginx-ingress-kubernetes-ioenable-cors">`nginx.ingress.kubernetes.io/enable-cors`</a> | Partial support. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocors-allow-credentials" href="#opt-nginx-ingress-kubernetes-iocors-allow-credentials" title="#opt-nginx-ingress-kubernetes-iocors-allow-credentials">`nginx.ingress.kubernetes.io/cors-allow-credentials`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocors-allow-headers" href="#opt-nginx-ingress-kubernetes-iocors-allow-headers" title="#opt-nginx-ingress-kubernetes-iocors-allow-headers">`nginx.ingress.kubernetes.io/cors-allow-headers`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocors-allow-methods" href="#opt-nginx-ingress-kubernetes-iocors-allow-methods" title="#opt-nginx-ingress-kubernetes-iocors-allow-methods">`nginx.ingress.kubernetes.io/cors-allow-methods`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocors-allow-origin" href="#opt-nginx-ingress-kubernetes-iocors-allow-origin" title="#opt-nginx-ingress-kubernetes-iocors-allow-origin">`nginx.ingress.kubernetes.io/cors-allow-origin`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocors-max-age" href="#opt-nginx-ingress-kubernetes-iocors-max-age" title="#opt-nginx-ingress-kubernetes-iocors-max-age">`nginx.ingress.kubernetes.io/cors-max-age`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-server-name">`nginx.ingress.kubernetes.io/proxy-ssl-server-name`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-name" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-name" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-name">`nginx.ingress.kubernetes.io/proxy-ssl-name`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-verify" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify">`nginx.ingress.kubernetes.io/proxy-ssl-verify`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-secret" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-secret" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-secret">`nginx.ingress.kubernetes.io/proxy-ssl-secret`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioservice-upstream" href="#opt-nginx-ingress-kubernetes-ioservice-upstream" title="#opt-nginx-ingress-kubernetes-ioservice-upstream">`nginx.ingress.kubernetes.io/service-upstream`</a> | |
|
||||
|
||||
### Unsupported NGINX Annotations
|
||||
### Routing
|
||||
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-iouse-regex" href="#opt-nginx-ingress-kubernetes-iouse-regex" title="#opt-nginx-ingress-kubernetes-iouse-regex">`nginx.ingress.kubernetes.io/use-regex`</a> | |
|
||||
|
||||
## Limitations
|
||||
|
||||
### Caveats and Key Behavioral Differences
|
||||
|
||||
- **Authentication**: Forward auth behaves differently and session caching is not supported. NGINX supports sub-request based auth, while Traefik forwards the original request.
|
||||
- **Session Affinity**: Only persistent mode is supported.
|
||||
- **Leader Election**: Not supported; no cluster mode with leader election.
|
||||
- **Default Backend**: Only defaultBackend in Ingress spec is supported; the annotation is ignored.
|
||||
- **Load Balancing**: Only round_robin is supported; EWMA and IP hash are not supported.
|
||||
- **CORS**: NGINX responds with all configured headers unconditionally; Traefik handles headers differently between pre-flight and regular requests.
|
||||
- **TLS/Backend Protocols**: AUTO_HTTP, FCGI and some TLS options are not supported in Traefik.
|
||||
- **Path Handling**: Traefik preserves trailing slashes by default; NGINX removes them unless configured otherwise
|
||||
|
||||
### Unsupported Annotations
|
||||
|
||||
!!! question "Want to Add Support for More Annotations?"
|
||||
|
||||
@@ -305,98 +334,103 @@ Limitations or behavioral differences are indicated where relevant.
|
||||
|
||||
All contributions and suggestions are welcome — let's build this together!
|
||||
|
||||
|
||||
| Annotation | Notes |
|
||||
|-----------------------------------------------------------------------------|------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioapp-root" href="#opt-nginx-ingress-kubernetes-ioapp-root" title="#opt-nginx-ingress-kubernetes-ioapp-root">`nginx.ingress.kubernetes.io/app-root`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior" href="#opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior" title="#opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior">`nginx.ingress.kubernetes.io/affinity-canary-behavior`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-secret" href="#opt-nginx-ingress-kubernetes-ioauth-tls-secret" title="#opt-nginx-ingress-kubernetes-ioauth-tls-secret">`nginx.ingress.kubernetes.io/auth-tls-secret`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth" href="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth" title="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth">`nginx.ingress.kubernetes.io/auth-tls-verify-depth`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-verify-client" href="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-client" title="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-client">`nginx.ingress.kubernetes.io/auth-tls-verify-client`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-error-page" href="#opt-nginx-ingress-kubernetes-ioauth-tls-error-page" title="#opt-nginx-ingress-kubernetes-ioauth-tls-error-page">`nginx.ingress.kubernetes.io/auth-tls-error-page`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream" href="#opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream" title="#opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream">`nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-match-cn" href="#opt-nginx-ingress-kubernetes-ioauth-tls-match-cn" title="#opt-nginx-ingress-kubernetes-ioauth-tls-match-cn">`nginx.ingress.kubernetes.io/auth-tls-match-cn`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-cache-key" href="#opt-nginx-ingress-kubernetes-ioauth-cache-key" title="#opt-nginx-ingress-kubernetes-ioauth-cache-key">`nginx.ingress.kubernetes.io/auth-cache-key`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-cache-duration" href="#opt-nginx-ingress-kubernetes-ioauth-cache-duration" title="#opt-nginx-ingress-kubernetes-ioauth-cache-duration">`nginx.ingress.kubernetes.io/auth-cache-duration`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive">`nginx.ingress.kubernetes.io/auth-keepalive`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars">`nginx.ingress.kubernetes.io/auth-keepalive-share-vars`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests">`nginx.ingress.kubernetes.io/auth-keepalive-requests`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout">`nginx.ingress.kubernetes.io/auth-keepalive-timeout`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" href="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" title="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers">`nginx.ingress.kubernetes.io/auth-proxy-set-headers`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-snippet" href="#opt-nginx-ingress-kubernetes-ioauth-snippet" title="#opt-nginx-ingress-kubernetes-ioauth-snippet">`nginx.ingress.kubernetes.io/auth-snippet`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-global-auth" href="#opt-nginx-ingress-kubernetes-ioenable-global-auth" title="#opt-nginx-ingress-kubernetes-ioenable-global-auth">`nginx.ingress.kubernetes.io/enable-global-auth`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary" href="#opt-nginx-ingress-kubernetes-iocanary" title="#opt-nginx-ingress-kubernetes-iocanary">`nginx.ingress.kubernetes.io/canary`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header" href="#opt-nginx-ingress-kubernetes-iocanary-by-header" title="#opt-nginx-ingress-kubernetes-iocanary-by-header">`nginx.ingress.kubernetes.io/canary-by-header`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header-value" href="#opt-nginx-ingress-kubernetes-iocanary-by-header-value" title="#opt-nginx-ingress-kubernetes-iocanary-by-header-value">`nginx.ingress.kubernetes.io/canary-by-header-value`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header-pattern" href="#opt-nginx-ingress-kubernetes-iocanary-by-header-pattern" title="#opt-nginx-ingress-kubernetes-iocanary-by-header-pattern">`nginx.ingress.kubernetes.io/canary-by-header-pattern`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-cookie" href="#opt-nginx-ingress-kubernetes-iocanary-by-cookie" title="#opt-nginx-ingress-kubernetes-iocanary-by-cookie">`nginx.ingress.kubernetes.io/canary-by-cookie`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-weight" href="#opt-nginx-ingress-kubernetes-iocanary-weight" title="#opt-nginx-ingress-kubernetes-iocanary-weight">`nginx.ingress.kubernetes.io/canary-weight`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-weight-total" href="#opt-nginx-ingress-kubernetes-iocanary-weight-total" title="#opt-nginx-ingress-kubernetes-iocanary-weight-total">`nginx.ingress.kubernetes.io/canary-weight-total`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioclient-body-buffer-size" href="#opt-nginx-ingress-kubernetes-ioclient-body-buffer-size" title="#opt-nginx-ingress-kubernetes-ioclient-body-buffer-size">`nginx.ingress.kubernetes.io/client-body-buffer-size`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioconfiguration-snippet" href="#opt-nginx-ingress-kubernetes-ioconfiguration-snippet" title="#opt-nginx-ingress-kubernetes-ioconfiguration-snippet">`nginx.ingress.kubernetes.io/configuration-snippet`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocustom-http-errors" href="#opt-nginx-ingress-kubernetes-iocustom-http-errors" title="#opt-nginx-ingress-kubernetes-iocustom-http-errors">`nginx.ingress.kubernetes.io/custom-http-errors`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" href="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" title="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors">`nginx.ingress.kubernetes.io/disable-proxy-intercept-errors`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodefault-backend" href="#opt-nginx-ingress-kubernetes-iodefault-backend" title="#opt-nginx-ingress-kubernetes-iodefault-backend">`nginx.ingress.kubernetes.io/default-backend`</a> | Not supported yet; use `defaultBackend` in Ingress spec. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate-after" href="#opt-nginx-ingress-kubernetes-iolimit-rate-after" title="#opt-nginx-ingress-kubernetes-iolimit-rate-after">`nginx.ingress.kubernetes.io/limit-rate-after`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate" href="#opt-nginx-ingress-kubernetes-iolimit-rate" title="#opt-nginx-ingress-kubernetes-iolimit-rate">`nginx.ingress.kubernetes.io/limit-rate`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-whitelist" href="#opt-nginx-ingress-kubernetes-iolimit-whitelist" title="#opt-nginx-ingress-kubernetes-iolimit-whitelist">`nginx.ingress.kubernetes.io/limit-whitelist`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rps" href="#opt-nginx-ingress-kubernetes-iolimit-rps" title="#opt-nginx-ingress-kubernetes-iolimit-rps">`nginx.ingress.kubernetes.io/limit-rps`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rpm" href="#opt-nginx-ingress-kubernetes-iolimit-rpm" title="#opt-nginx-ingress-kubernetes-iolimit-rpm">`nginx.ingress.kubernetes.io/limit-rpm`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-burst-multiplier" href="#opt-nginx-ingress-kubernetes-iolimit-burst-multiplier" title="#opt-nginx-ingress-kubernetes-iolimit-burst-multiplier">`nginx.ingress.kubernetes.io/limit-burst-multiplier`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-connections" href="#opt-nginx-ingress-kubernetes-iolimit-connections" title="#opt-nginx-ingress-kubernetes-iolimit-connections">`nginx.ingress.kubernetes.io/limit-connections`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit">`nginx.ingress.kubernetes.io/global-rate-limit`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window">`nginx.ingress.kubernetes.io/global-rate-limit-window`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key">`nginx.ingress.kubernetes.io/global-rate-limit-key`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs">`nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect">`nginx.ingress.kubernetes.io/permanent-redirect`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect-code" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code">`nginx.ingress.kubernetes.io/permanent-redirect-code`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iotemporal-redirect" href="#opt-nginx-ingress-kubernetes-iotemporal-redirect" title="#opt-nginx-ingress-kubernetes-iotemporal-redirect">`nginx.ingress.kubernetes.io/temporal-redirect`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" href="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" title="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash">`nginx.ingress.kubernetes.io/preserve-trailing-slash`</a> | Not supported yet; Traefik preserves by default. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain">`nginx.ingress.kubernetes.io/proxy-cookie-domain`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-path" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path">`nginx.ingress.kubernetes.io/proxy-cookie-path`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-connect-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-connect-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-connect-timeout">`nginx.ingress.kubernetes.io/proxy-connect-timeout`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-send-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-send-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-send-timeout">`nginx.ingress.kubernetes.io/proxy-send-timeout`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-read-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-read-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-read-timeout">`nginx.ingress.kubernetes.io/proxy-read-timeout`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream">`nginx.ingress.kubernetes.io/proxy-next-upstream`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout">`nginx.ingress.kubernetes.io/proxy-next-upstream-timeout`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries">`nginx.ingress.kubernetes.io/proxy-next-upstream-tries`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-request-buffering" href="#opt-nginx-ingress-kubernetes-ioproxy-request-buffering" title="#opt-nginx-ingress-kubernetes-ioproxy-request-buffering">`nginx.ingress.kubernetes.io/proxy-request-buffering`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-redirect-from" href="#opt-nginx-ingress-kubernetes-ioproxy-redirect-from" title="#opt-nginx-ingress-kubernetes-ioproxy-redirect-from">`nginx.ingress.kubernetes.io/proxy-redirect-from`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-redirect-to" href="#opt-nginx-ingress-kubernetes-ioproxy-redirect-to" title="#opt-nginx-ingress-kubernetes-ioproxy-redirect-to">`nginx.ingress.kubernetes.io/proxy-redirect-to`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-http-version" href="#opt-nginx-ingress-kubernetes-ioproxy-http-version" title="#opt-nginx-ingress-kubernetes-ioproxy-http-version">`nginx.ingress.kubernetes.io/proxy-http-version`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers">`nginx.ingress.kubernetes.io/proxy-ssl-ciphers`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth">`nginx.ingress.kubernetes.io/proxy-ssl-verify-depth`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols">`nginx.ingress.kubernetes.io/proxy-ssl-protocols`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-rewrite-log" href="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log" title="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log">`nginx.ingress.kubernetes.io/enable-rewrite-log`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iorewrite-target" href="#opt-nginx-ingress-kubernetes-iorewrite-target" title="#opt-nginx-ingress-kubernetes-iorewrite-target">`nginx.ingress.kubernetes.io/rewrite-target`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosatisfy" href="#opt-nginx-ingress-kubernetes-iosatisfy" title="#opt-nginx-ingress-kubernetes-iosatisfy">`nginx.ingress.kubernetes.io/satisfy`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-alias" href="#opt-nginx-ingress-kubernetes-ioserver-alias" title="#opt-nginx-ingress-kubernetes-ioserver-alias">`nginx.ingress.kubernetes.io/server-alias`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-snippet" href="#opt-nginx-ingress-kubernetes-ioserver-snippet" title="#opt-nginx-ingress-kubernetes-ioserver-snippet">`nginx.ingress.kubernetes.io/server-snippet`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" href="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" title="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none">`nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-expires" href="#opt-nginx-ingress-kubernetes-iosession-cookie-expires" title="#opt-nginx-ingress-kubernetes-iosession-cookie-expires">`nginx.ingress.kubernetes.io/session-cookie-expires`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" href="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" title="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure">`nginx.ingress.kubernetes.io/session-cookie-change-on-failure`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-ciphers">`nginx.ingress.kubernetes.io/ssl-ciphers`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers">`nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioconnection-proxy-header" href="#opt-nginx-ingress-kubernetes-ioconnection-proxy-header" title="#opt-nginx-ingress-kubernetes-ioconnection-proxy-header">`nginx.ingress.kubernetes.io/connection-proxy-header`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-access-log" href="#opt-nginx-ingress-kubernetes-ioenable-access-log" title="#opt-nginx-ingress-kubernetes-ioenable-access-log">`nginx.ingress.kubernetes.io/enable-access-log`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-opentracing" href="#opt-nginx-ingress-kubernetes-ioenable-opentracing" title="#opt-nginx-ingress-kubernetes-ioenable-opentracing">`nginx.ingress.kubernetes.io/enable-opentracing`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span" href="#opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span" title="#opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span">`nginx.ingress.kubernetes.io/opentracing-trust-incoming-span`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-opentelemetry" href="#opt-nginx-ingress-kubernetes-ioenable-opentelemetry" title="#opt-nginx-ingress-kubernetes-ioenable-opentelemetry">`nginx.ingress.kubernetes.io/enable-opentelemetry`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span" href="#opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span" title="#opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span">`nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-modsecurity" href="#opt-nginx-ingress-kubernetes-ioenable-modsecurity" title="#opt-nginx-ingress-kubernetes-ioenable-modsecurity">`nginx.ingress.kubernetes.io/enable-modsecurity`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules" href="#opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules" title="#opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules">`nginx.ingress.kubernetes.io/enable-owasp-core-rules`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id" href="#opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id" title="#opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id">`nginx.ingress.kubernetes.io/modsecurity-transaction-id`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomodsecurity-snippet" href="#opt-nginx-ingress-kubernetes-iomodsecurity-snippet" title="#opt-nginx-ingress-kubernetes-iomodsecurity-snippet">`nginx.ingress.kubernetes.io/modsecurity-snippet`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-request-body" href="#opt-nginx-ingress-kubernetes-iomirror-request-body" title="#opt-nginx-ingress-kubernetes-iomirror-request-body">`nginx.ingress.kubernetes.io/mirror-request-body`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-target" href="#opt-nginx-ingress-kubernetes-iomirror-target" title="#opt-nginx-ingress-kubernetes-iomirror-target">`nginx.ingress.kubernetes.io/mirror-target`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-host" href="#opt-nginx-ingress-kubernetes-iomirror-host" title="#opt-nginx-ingress-kubernetes-iomirror-host">`nginx.ingress.kubernetes.io/mirror-host`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iox-forwarded-prefix" href="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix" title="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix">`nginx.ingress.kubernetes.io/x-forwarded-prefix`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioupstream-hash-by" href="#opt-nginx-ingress-kubernetes-ioupstream-hash-by" title="#opt-nginx-ingress-kubernetes-ioupstream-hash-by">`nginx.ingress.kubernetes.io/upstream-hash-by`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioupstream-vhost" href="#opt-nginx-ingress-kubernetes-ioupstream-vhost" title="#opt-nginx-ingress-kubernetes-ioupstream-vhost">`nginx.ingress.kubernetes.io/upstream-vhost`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodenylist-source-range" href="#opt-nginx-ingress-kubernetes-iodenylist-source-range" title="#opt-nginx-ingress-kubernetes-iodenylist-source-range">`nginx.ingress.kubernetes.io/denylist-source-range`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iowhitelist-source-range" href="#opt-nginx-ingress-kubernetes-iowhitelist-source-range" title="#opt-nginx-ingress-kubernetes-iowhitelist-source-range">`nginx.ingress.kubernetes.io/whitelist-source-range`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffering" href="#opt-nginx-ingress-kubernetes-ioproxy-buffering" title="#opt-nginx-ingress-kubernetes-ioproxy-buffering">`nginx.ingress.kubernetes.io/proxy-buffering`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffers-number" href="#opt-nginx-ingress-kubernetes-ioproxy-buffers-number" title="#opt-nginx-ingress-kubernetes-ioproxy-buffers-number">`nginx.ingress.kubernetes.io/proxy-buffers-number`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffer-size" href="#opt-nginx-ingress-kubernetes-ioproxy-buffer-size" title="#opt-nginx-ingress-kubernetes-ioproxy-buffer-size">`nginx.ingress.kubernetes.io/proxy-buffer-size`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size" href="#opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size" title="#opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size">`nginx.ingress.kubernetes.io/proxy-max-temp-file-size`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iostream-snippet" href="#opt-nginx-ingress-kubernetes-iostream-snippet" title="#opt-nginx-ingress-kubernetes-iostream-snippet">`nginx.ingress.kubernetes.io/stream-snippet`</a> | Not supported yet. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioapp-root" href="#opt-nginx-ingress-kubernetes-ioapp-root" title="#opt-nginx-ingress-kubernetes-ioapp-root">`nginx.ingress.kubernetes.io/app-root`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior" href="#opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior" title="#opt-nginx-ingress-kubernetes-ioaffinity-canary-behavior">`nginx.ingress.kubernetes.io/affinity-canary-behavior`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-secret" href="#opt-nginx-ingress-kubernetes-ioauth-tls-secret" title="#opt-nginx-ingress-kubernetes-ioauth-tls-secret">`nginx.ingress.kubernetes.io/auth-tls-secret`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth" href="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth" title="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-depth">`nginx.ingress.kubernetes.io/auth-tls-verify-depth`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-verify-client" href="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-client" title="#opt-nginx-ingress-kubernetes-ioauth-tls-verify-client">`nginx.ingress.kubernetes.io/auth-tls-verify-client`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-error-page" href="#opt-nginx-ingress-kubernetes-ioauth-tls-error-page" title="#opt-nginx-ingress-kubernetes-ioauth-tls-error-page">`nginx.ingress.kubernetes.io/auth-tls-error-page`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream" href="#opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream" title="#opt-nginx-ingress-kubernetes-ioauth-tls-pass-certificate-to-upstream">`nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-tls-match-cn" href="#opt-nginx-ingress-kubernetes-ioauth-tls-match-cn" title="#opt-nginx-ingress-kubernetes-ioauth-tls-match-cn">`nginx.ingress.kubernetes.io/auth-tls-match-cn`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-cache-key" href="#opt-nginx-ingress-kubernetes-ioauth-cache-key" title="#opt-nginx-ingress-kubernetes-ioauth-cache-key">`nginx.ingress.kubernetes.io/auth-cache-key`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-cache-duration" href="#opt-nginx-ingress-kubernetes-ioauth-cache-duration" title="#opt-nginx-ingress-kubernetes-ioauth-cache-duration">`nginx.ingress.kubernetes.io/auth-cache-duration`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive">`nginx.ingress.kubernetes.io/auth-keepalive`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-share-vars">`nginx.ingress.kubernetes.io/auth-keepalive-share-vars`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests">`nginx.ingress.kubernetes.io/auth-keepalive-requests`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout">`nginx.ingress.kubernetes.io/auth-keepalive-timeout`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" href="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" title="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers">`nginx.ingress.kubernetes.io/auth-proxy-set-headers`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioauth-snippet" href="#opt-nginx-ingress-kubernetes-ioauth-snippet" title="#opt-nginx-ingress-kubernetes-ioauth-snippet">`nginx.ingress.kubernetes.io/auth-snippet`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-global-auth" href="#opt-nginx-ingress-kubernetes-ioenable-global-auth" title="#opt-nginx-ingress-kubernetes-ioenable-global-auth">`nginx.ingress.kubernetes.io/enable-global-auth`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary" href="#opt-nginx-ingress-kubernetes-iocanary" title="#opt-nginx-ingress-kubernetes-iocanary">`nginx.ingress.kubernetes.io/canary`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header" href="#opt-nginx-ingress-kubernetes-iocanary-by-header" title="#opt-nginx-ingress-kubernetes-iocanary-by-header">`nginx.ingress.kubernetes.io/canary-by-header`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header-value" href="#opt-nginx-ingress-kubernetes-iocanary-by-header-value" title="#opt-nginx-ingress-kubernetes-iocanary-by-header-value">`nginx.ingress.kubernetes.io/canary-by-header-value`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-header-pattern" href="#opt-nginx-ingress-kubernetes-iocanary-by-header-pattern" title="#opt-nginx-ingress-kubernetes-iocanary-by-header-pattern">`nginx.ingress.kubernetes.io/canary-by-header-pattern`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-by-cookie" href="#opt-nginx-ingress-kubernetes-iocanary-by-cookie" title="#opt-nginx-ingress-kubernetes-iocanary-by-cookie">`nginx.ingress.kubernetes.io/canary-by-cookie`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-weight" href="#opt-nginx-ingress-kubernetes-iocanary-weight" title="#opt-nginx-ingress-kubernetes-iocanary-weight">`nginx.ingress.kubernetes.io/canary-weight`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocanary-weight-total" href="#opt-nginx-ingress-kubernetes-iocanary-weight-total" title="#opt-nginx-ingress-kubernetes-iocanary-weight-total">`nginx.ingress.kubernetes.io/canary-weight-total`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioclient-body-buffer-size" href="#opt-nginx-ingress-kubernetes-ioclient-body-buffer-size" title="#opt-nginx-ingress-kubernetes-ioclient-body-buffer-size">`nginx.ingress.kubernetes.io/client-body-buffer-size`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioconfiguration-snippet" href="#opt-nginx-ingress-kubernetes-ioconfiguration-snippet" title="#opt-nginx-ingress-kubernetes-ioconfiguration-snippet">`nginx.ingress.kubernetes.io/configuration-snippet`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iocustom-http-errors" href="#opt-nginx-ingress-kubernetes-iocustom-http-errors" title="#opt-nginx-ingress-kubernetes-iocustom-http-errors">`nginx.ingress.kubernetes.io/custom-http-errors`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" href="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" title="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors">`nginx.ingress.kubernetes.io/disable-proxy-intercept-errors`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodefault-backend" href="#opt-nginx-ingress-kubernetes-iodefault-backend" title="#opt-nginx-ingress-kubernetes-iodefault-backend">`nginx.ingress.kubernetes.io/default-backend`</a> | Use `defaultBackend` in Ingress spec. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate-after" href="#opt-nginx-ingress-kubernetes-iolimit-rate-after" title="#opt-nginx-ingress-kubernetes-iolimit-rate-after">`nginx.ingress.kubernetes.io/limit-rate-after`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate" href="#opt-nginx-ingress-kubernetes-iolimit-rate" title="#opt-nginx-ingress-kubernetes-iolimit-rate">`nginx.ingress.kubernetes.io/limit-rate`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-whitelist" href="#opt-nginx-ingress-kubernetes-iolimit-whitelist" title="#opt-nginx-ingress-kubernetes-iolimit-whitelist">`nginx.ingress.kubernetes.io/limit-whitelist`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rps" href="#opt-nginx-ingress-kubernetes-iolimit-rps" title="#opt-nginx-ingress-kubernetes-iolimit-rps">`nginx.ingress.kubernetes.io/limit-rps`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-rpm" href="#opt-nginx-ingress-kubernetes-iolimit-rpm" title="#opt-nginx-ingress-kubernetes-iolimit-rpm">`nginx.ingress.kubernetes.io/limit-rpm`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-burst-multiplier" href="#opt-nginx-ingress-kubernetes-iolimit-burst-multiplier" title="#opt-nginx-ingress-kubernetes-iolimit-burst-multiplier">`nginx.ingress.kubernetes.io/limit-burst-multiplier`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iolimit-connections" href="#opt-nginx-ingress-kubernetes-iolimit-connections" title="#opt-nginx-ingress-kubernetes-iolimit-connections">`nginx.ingress.kubernetes.io/limit-connections`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit">`nginx.ingress.kubernetes.io/global-rate-limit`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window">`nginx.ingress.kubernetes.io/global-rate-limit-window`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key">`nginx.ingress.kubernetes.io/global-rate-limit-key`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs">`nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect">`nginx.ingress.kubernetes.io/permanent-redirect`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect-code" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code">`nginx.ingress.kubernetes.io/permanent-redirect-code`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iotemporal-redirect" href="#opt-nginx-ingress-kubernetes-iotemporal-redirect" title="#opt-nginx-ingress-kubernetes-iotemporal-redirect">`nginx.ingress.kubernetes.io/temporal-redirect`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" href="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" title="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash">`nginx.ingress.kubernetes.io/preserve-trailing-slash`</a> | Traefik preserves trailing slash by default. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain">`nginx.ingress.kubernetes.io/proxy-cookie-domain`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-path" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path">`nginx.ingress.kubernetes.io/proxy-cookie-path`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-connect-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-connect-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-connect-timeout">`nginx.ingress.kubernetes.io/proxy-connect-timeout`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-send-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-send-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-send-timeout">`nginx.ingress.kubernetes.io/proxy-send-timeout`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-read-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-read-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-read-timeout">`nginx.ingress.kubernetes.io/proxy-read-timeout`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream">`nginx.ingress.kubernetes.io/proxy-next-upstream`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-timeout">`nginx.ingress.kubernetes.io/proxy-next-upstream-timeout`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries" href="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries" title="#opt-nginx-ingress-kubernetes-ioproxy-next-upstream-tries">`nginx.ingress.kubernetes.io/proxy-next-upstream-tries`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-request-buffering" href="#opt-nginx-ingress-kubernetes-ioproxy-request-buffering" title="#opt-nginx-ingress-kubernetes-ioproxy-request-buffering">`nginx.ingress.kubernetes.io/proxy-request-buffering`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-redirect-from" href="#opt-nginx-ingress-kubernetes-ioproxy-redirect-from" title="#opt-nginx-ingress-kubernetes-ioproxy-redirect-from">`nginx.ingress.kubernetes.io/proxy-redirect-from`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-redirect-to" href="#opt-nginx-ingress-kubernetes-ioproxy-redirect-to" title="#opt-nginx-ingress-kubernetes-ioproxy-redirect-to">`nginx.ingress.kubernetes.io/proxy-redirect-to`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-http-version" href="#opt-nginx-ingress-kubernetes-ioproxy-http-version" title="#opt-nginx-ingress-kubernetes-ioproxy-http-version">`nginx.ingress.kubernetes.io/proxy-http-version`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-ciphers">`nginx.ingress.kubernetes.io/proxy-ssl-ciphers`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth">`nginx.ingress.kubernetes.io/proxy-ssl-verify-depth`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols">`nginx.ingress.kubernetes.io/proxy-ssl-protocols`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-rewrite-log" href="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log" title="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log">`nginx.ingress.kubernetes.io/enable-rewrite-log`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iorewrite-target" href="#opt-nginx-ingress-kubernetes-iorewrite-target" title="#opt-nginx-ingress-kubernetes-iorewrite-target">`nginx.ingress.kubernetes.io/rewrite-target`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosatisfy" href="#opt-nginx-ingress-kubernetes-iosatisfy" title="#opt-nginx-ingress-kubernetes-iosatisfy">`nginx.ingress.kubernetes.io/satisfy`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-alias" href="#opt-nginx-ingress-kubernetes-ioserver-alias" title="#opt-nginx-ingress-kubernetes-ioserver-alias">`nginx.ingress.kubernetes.io/server-alias`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-snippet" href="#opt-nginx-ingress-kubernetes-ioserver-snippet" title="#opt-nginx-ingress-kubernetes-ioserver-snippet">`nginx.ingress.kubernetes.io/server-snippet`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" href="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" title="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none">`nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-expires" href="#opt-nginx-ingress-kubernetes-iosession-cookie-expires" title="#opt-nginx-ingress-kubernetes-iosession-cookie-expires">`nginx.ingress.kubernetes.io/session-cookie-expires`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" href="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" title="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure">`nginx.ingress.kubernetes.io/session-cookie-change-on-failure`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-ciphers">`nginx.ingress.kubernetes.io/ssl-ciphers`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers">`nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioconnection-proxy-header" href="#opt-nginx-ingress-kubernetes-ioconnection-proxy-header" title="#opt-nginx-ingress-kubernetes-ioconnection-proxy-header">`nginx.ingress.kubernetes.io/connection-proxy-header`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-access-log" href="#opt-nginx-ingress-kubernetes-ioenable-access-log" title="#opt-nginx-ingress-kubernetes-ioenable-access-log">`nginx.ingress.kubernetes.io/enable-access-log`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-opentracing" href="#opt-nginx-ingress-kubernetes-ioenable-opentracing" title="#opt-nginx-ingress-kubernetes-ioenable-opentracing">`nginx.ingress.kubernetes.io/enable-opentracing`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span" href="#opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span" title="#opt-nginx-ingress-kubernetes-ioopentracing-trust-incoming-span">`nginx.ingress.kubernetes.io/opentracing-trust-incoming-span`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-opentelemetry" href="#opt-nginx-ingress-kubernetes-ioenable-opentelemetry" title="#opt-nginx-ingress-kubernetes-ioenable-opentelemetry">`nginx.ingress.kubernetes.io/enable-opentelemetry`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span" href="#opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span" title="#opt-nginx-ingress-kubernetes-ioopentelemetry-trust-incoming-span">`nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-modsecurity" href="#opt-nginx-ingress-kubernetes-ioenable-modsecurity" title="#opt-nginx-ingress-kubernetes-ioenable-modsecurity">`nginx.ingress.kubernetes.io/enable-modsecurity`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules" href="#opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules" title="#opt-nginx-ingress-kubernetes-ioenable-owasp-core-rules">`nginx.ingress.kubernetes.io/enable-owasp-core-rules`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id" href="#opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id" title="#opt-nginx-ingress-kubernetes-iomodsecurity-transaction-id">`nginx.ingress.kubernetes.io/modsecurity-transaction-id`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomodsecurity-snippet" href="#opt-nginx-ingress-kubernetes-iomodsecurity-snippet" title="#opt-nginx-ingress-kubernetes-iomodsecurity-snippet">`nginx.ingress.kubernetes.io/modsecurity-snippet`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-request-body" href="#opt-nginx-ingress-kubernetes-iomirror-request-body" title="#opt-nginx-ingress-kubernetes-iomirror-request-body">`nginx.ingress.kubernetes.io/mirror-request-body`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-target" href="#opt-nginx-ingress-kubernetes-iomirror-target" title="#opt-nginx-ingress-kubernetes-iomirror-target">`nginx.ingress.kubernetes.io/mirror-target`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iomirror-host" href="#opt-nginx-ingress-kubernetes-iomirror-host" title="#opt-nginx-ingress-kubernetes-iomirror-host">`nginx.ingress.kubernetes.io/mirror-host`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iox-forwarded-prefix" href="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix" title="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix">`nginx.ingress.kubernetes.io/x-forwarded-prefix`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioupstream-hash-by" href="#opt-nginx-ingress-kubernetes-ioupstream-hash-by" title="#opt-nginx-ingress-kubernetes-ioupstream-hash-by">`nginx.ingress.kubernetes.io/upstream-hash-by`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioupstream-vhost" href="#opt-nginx-ingress-kubernetes-ioupstream-vhost" title="#opt-nginx-ingress-kubernetes-ioupstream-vhost">`nginx.ingress.kubernetes.io/upstream-vhost`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iodenylist-source-range" href="#opt-nginx-ingress-kubernetes-iodenylist-source-range" title="#opt-nginx-ingress-kubernetes-iodenylist-source-range">`nginx.ingress.kubernetes.io/denylist-source-range`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iowhitelist-source-range" href="#opt-nginx-ingress-kubernetes-iowhitelist-source-range" title="#opt-nginx-ingress-kubernetes-iowhitelist-source-range">`nginx.ingress.kubernetes.io/whitelist-source-range`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffering" href="#opt-nginx-ingress-kubernetes-ioproxy-buffering" title="#opt-nginx-ingress-kubernetes-ioproxy-buffering">`nginx.ingress.kubernetes.io/proxy-buffering`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffers-number" href="#opt-nginx-ingress-kubernetes-ioproxy-buffers-number" title="#opt-nginx-ingress-kubernetes-ioproxy-buffers-number">`nginx.ingress.kubernetes.io/proxy-buffers-number`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffer-size" href="#opt-nginx-ingress-kubernetes-ioproxy-buffer-size" title="#opt-nginx-ingress-kubernetes-ioproxy-buffer-size">`nginx.ingress.kubernetes.io/proxy-buffer-size`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size" href="#opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size" title="#opt-nginx-ingress-kubernetes-ioproxy-max-temp-file-size">`nginx.ingress.kubernetes.io/proxy-max-temp-file-size`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iostream-snippet" href="#opt-nginx-ingress-kubernetes-iostream-snippet" title="#opt-nginx-ingress-kubernetes-iostream-snippet">`nginx.ingress.kubernetes.io/stream-snippet`</a> | |
|
||||
|
||||
### Global Configuration
|
||||
|
||||
Traefik does not expose all global configuration options to control default behaviors for Ingresses in the same way NGINX does.
|
||||
|
||||
Some behaviors that are globally configurable in NGINX (such as default SSL redirect, rate limiting, or affinity) are currently not supported and cannot be overridden per-Ingress as in NGINX. These limitations are noted in the annotation tables below where applicable.
|
||||
|
||||
@@ -285,6 +285,15 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||
"traefik.http.services.myservice.loadbalancer.server.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
|
||||
|
||||
Defines the service URL.
|
||||
This option cannot be used in combination with `port` or `scheme` definition.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.<service_name>.loadbalancer.server.url=http://foobar:8080
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
|
||||
@@ -301,6 +301,15 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||
- "traefik.http.services.myservice.loadbalancer.server.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
|
||||
|
||||
Defines the service URL.
|
||||
This option cannot be used in combination with `port` or `scheme` definition.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.<service_name>.loadbalancer.server.url=http://foobar:8080
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.weight`"
|
||||
|
||||
Overrides the default weight.
|
||||
|
||||
@@ -255,7 +255,7 @@ HighestRandomWeight, also called RendezVous hashing allows to loadbalance client
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
type: hrw
|
||||
strategy: hrw
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
- url: "http://private-ip-server-2/"
|
||||
@@ -1306,13 +1306,13 @@ http:
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
type: hrw
|
||||
strategy: hrw
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
type: hrw
|
||||
strategy: hrw
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/"
|
||||
```
|
||||
@@ -1330,13 +1330,13 @@ http:
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
type = "hrw"
|
||||
strategy = "hrw"
|
||||
[[http.services.appv1.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
type = "hrw"
|
||||
strategy = "hrw"
|
||||
[[http.services.appv2.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
||||
@@ -1371,7 +1371,7 @@ http:
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
type: hrw
|
||||
strategy: hrw
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
@@ -1381,7 +1381,7 @@ http:
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
type: hrw
|
||||
strategy: hrw
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
@@ -1404,7 +1404,7 @@ http:
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
type="hrw"
|
||||
strategy="hrw"
|
||||
[http.services.appv1.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
@@ -1414,7 +1414,7 @@ http:
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
type="hrw"
|
||||
strategy="hrw"
|
||||
[http.services.appv2.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server:
|
||||
image: rancher/k3s:v1.17.2-k3s1
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
command: server --disable-agent --no-deploy traefik
|
||||
environment:
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
@@ -17,7 +17,7 @@ server:
|
||||
- 6443:6443
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v1.17.2-k3s1
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
privileged: true
|
||||
links:
|
||||
- server
|
||||
|
||||
@@ -55,7 +55,7 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo.
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/prometheus/client_model v0.6.2
|
||||
github.com/quic-go/quic-go v0.55.0
|
||||
github.com/quic-go/quic-go v0.57.0
|
||||
github.com/redis/go-redis/v9 v9.8.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
@@ -95,14 +95,14 @@ require (
|
||||
go.opentelemetry.io/otel/sdk/log v0.14.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
golang.org/x/mod v0.28.0
|
||||
golang.org/x/net v0.46.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.37.0
|
||||
golang.org/x/text v0.30.0
|
||||
golang.org/x/crypto v0.45.0
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/net v0.47.0
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/text v0.31.0
|
||||
golang.org/x/time v0.14.0
|
||||
golang.org/x/tools v0.37.0
|
||||
golang.org/x/tools v0.38.0
|
||||
google.golang.org/grpc v1.76.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -322,7 +322,7 @@ require (
|
||||
github.com/pquerna/otp v1.5.0 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
|
||||
@@ -388,9 +388,9 @@ require (
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/api v0.254.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
|
||||
@@ -1112,10 +1112,10 @@ github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUO
|
||||
github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0=
|
||||
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE=
|
||||
github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||
@@ -1507,8 +1507,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1522,8 +1522,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
@@ -1553,8 +1553,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1617,8 +1617,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1644,8 +1644,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1743,8 +1743,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1761,8 +1761,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1781,8 +1781,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1852,8 +1852,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -42,7 +42,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
k3sImage = "docker.io/rancher/k3s:v1.32.9-k3s1"
|
||||
k3sImage = "docker.io/rancher/k3s:v1.34.2-k3s1"
|
||||
traefikImage = "traefik/traefik:latest"
|
||||
traefikDeployment = "deployments/traefik"
|
||||
traefikNamespace = "traefik"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:v1.21.14-k3s1
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
privileged: true
|
||||
command:
|
||||
- server
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- ./fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v1.21.14-k3s1
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
privileged: true
|
||||
environment:
|
||||
K3S_TOKEN: somethingtotallyrandom
|
||||
|
||||
@@ -570,6 +570,7 @@ func (i *ingress) deprecationNotice(logger zerolog.Logger) {
|
||||
type experimental struct {
|
||||
HTTP3 *bool `json:"http3,omitempty" toml:"http3,omitempty" yaml:"http3,omitempty"`
|
||||
KubernetesGateway *bool `json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty"`
|
||||
KubernetesIngressNGINX *bool `json:"kubernetesIngressNGINX,omitempty" toml:"kubernetesIngressNGINX,omitempty" yaml:"kubernetesIngressNGINX,omitempty"`
|
||||
}
|
||||
|
||||
func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
||||
@@ -591,6 +592,12 @@ func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
||||
" For more information please read the migration guide: https://doc.traefik.io/traefik/v3.6/migration/v3/#gateway-api-kubernetesgateway-provider")
|
||||
}
|
||||
|
||||
if e.KubernetesIngressNGINX != nil {
|
||||
logger.Error().Msg("KubernetesIngressNGINX provider is not an experimental feature starting with v3.6.2." +
|
||||
" Please remove its usage from the install configuration." +
|
||||
" For more information please read the migration guide: https://doc.traefik.io/traefik/v3.6/migration/v3/#ingress-nginx-provider")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@ type Experimental struct {
|
||||
FastProxy *FastProxyConfig `description:"Enables the FastProxy implementation." json:"fastProxy,omitempty" toml:"fastProxy,omitempty" yaml:"fastProxy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
OTLPLogs bool `description:"Enables the OpenTelemetry logs integration." json:"otlplogs,omitempty" toml:"otlplogs,omitempty" yaml:"otlplogs,omitempty" export:"true"`
|
||||
Knative bool `description:"Allow the Knative provider usage." json:"knative,omitempty" toml:"knative,omitempty" yaml:"knative,omitempty" export:"true"`
|
||||
KubernetesIngressNGINX bool `description:"Allow the Kubernetes Ingress NGINX provider usage." json:"kubernetesIngressNGINX,omitempty" toml:"kubernetesIngressNGINX,omitempty" yaml:"kubernetesIngressNGINX,omitempty" export:"true"`
|
||||
|
||||
// Deprecated: KubernetesIngressNGINX provider is not an experimental feature starting with v3.6.2. Please remove its usage from the static configuration.
|
||||
KubernetesIngressNGINX bool `description:"Allow the Kubernetes Ingress NGINX provider usage." json:"kubernetesIngressNGINX,omitempty" toml:"kubernetesIngressNGINX,omitempty" yaml:"kubernetesIngressNGINX,omitempty" export:"true"`
|
||||
// Deprecated: KubernetesGateway provider is not an experimental feature starting with v3.1. Please remove its usage from the static configuration.
|
||||
KubernetesGateway bool `description:"(Deprecated) Allow the Kubernetes gateway api provider usage." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
@@ -424,10 +424,6 @@ func (c *Configuration) ValidateConfiguration() error {
|
||||
}
|
||||
|
||||
if c.Providers != nil && c.Providers.KubernetesIngressNGINX != nil {
|
||||
if c.Experimental == nil || !c.Experimental.KubernetesIngressNGINX {
|
||||
return errors.New("the experimental KubernetesIngressNGINX feature must be enabled to use the KubernetesIngressNGINX provider")
|
||||
}
|
||||
|
||||
if c.Providers.KubernetesIngressNGINX.WatchNamespace != "" && c.Providers.KubernetesIngressNGINX.WatchNamespaceSelector != "" {
|
||||
return errors.New("watchNamespace and watchNamespaceSelector options are mutually exclusive")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
const localGoPath = "./plugins-local/"
|
||||
@@ -53,24 +54,18 @@ func checkRemotePluginsConfiguration(plugins map[string]Descriptor) error {
|
||||
|
||||
var errs []string
|
||||
for pAlias, descriptor := range plugins {
|
||||
if descriptor.ModuleName == "" {
|
||||
errs = append(errs, fmt.Sprintf("%s: plugin name is missing", pAlias))
|
||||
if err := module.CheckPath(descriptor.ModuleName); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("%s: malformed plugin module name is missing: %s", pAlias, err))
|
||||
}
|
||||
|
||||
if descriptor.Version == "" {
|
||||
errs = append(errs, fmt.Sprintf("%s: plugin version is missing", pAlias))
|
||||
}
|
||||
|
||||
if strings.HasPrefix(descriptor.ModuleName, "/") || strings.HasSuffix(descriptor.ModuleName, "/") {
|
||||
errs = append(errs, fmt.Sprintf("%s: plugin name should not start or end with a /", pAlias))
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := uniq[descriptor.ModuleName]; ok {
|
||||
errs = append(errs, fmt.Sprintf("only one version of a plugin is allowed, there is a duplicate of %s", descriptor.ModuleName))
|
||||
continue
|
||||
}
|
||||
|
||||
uniq[descriptor.ModuleName] = struct{}{}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_checkRemotePluginsConfiguration(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
plugins map[string]Descriptor
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "nil plugins configuration returns no error",
|
||||
plugins: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "malformed module name returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "invalid/module/name", Version: "v1.0.0"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "malformed module name with path traversal returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "github.com/module/../name", Version: "v1.0.0"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "malformed module name with encoded path traversal returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "github.com/module%2F%2E%2E%2Fname", Version: "v1.0.0"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "malformed module name returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "invalid/module/name", Version: "v1.0.0"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing plugin version returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "github.com/module/name", Version: ""},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "duplicate plugin module name returns error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "github.com/module/name", Version: "v1.0.0"},
|
||||
"plugin2": {ModuleName: "github.com/module/name", Version: "v1.1.0"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "valid plugins configuration returns no error",
|
||||
plugins: map[string]Descriptor{
|
||||
"plugin1": {ModuleName: "github.com/module/name1", Version: "v1.0.0"},
|
||||
"plugin2": {ModuleName: "github.com/module/name2", Version: "v1.1.0"},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := checkRemotePluginsConfiguration(test.plugins)
|
||||
if test.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,6 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/safe"
|
||||
)
|
||||
|
||||
// DockerAPIVersion is a constant holding the version of the Provider API traefik will use.
|
||||
const DockerAPIVersion = "1.24"
|
||||
|
||||
const dockerName = "docker"
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
@@ -54,7 +51,6 @@ func (p *Provider) Init() error {
|
||||
}
|
||||
|
||||
func (p *Provider) createClient(ctx context.Context) (*client.Client, error) {
|
||||
p.ClientConfig.apiVersion = DockerAPIVersion
|
||||
return createClient(ctx, p.ClientConfig)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/safe"
|
||||
)
|
||||
|
||||
// SwarmAPIVersion is a constant holding the version of the Provider API traefik will use.
|
||||
const SwarmAPIVersion = "1.24"
|
||||
|
||||
const swarmName = "swarm"
|
||||
|
||||
var _ provider.Provider = (*SwarmProvider)(nil)
|
||||
@@ -58,7 +55,6 @@ func (p *SwarmProvider) Init() error {
|
||||
}
|
||||
|
||||
func (p *SwarmProvider) createClient(ctx context.Context) (*client.Client, error) {
|
||||
p.ClientConfig.apiVersion = SwarmAPIVersion
|
||||
return createClient(ctx, p.ClientConfig)
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +100,6 @@ func parseContainer(container containertypes.InspectResponse) dockerData {
|
||||
}
|
||||
|
||||
type ClientConfig struct {
|
||||
apiVersion string
|
||||
|
||||
Username string `description:"Username for Basic HTTP authentication." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
|
||||
Password string `description:"Password for Basic HTTP authentication." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
|
||||
Endpoint string `description:"Docker server endpoint. Can be a TCP or a Unix socket endpoint." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||
@@ -123,8 +121,9 @@ func createClient(ctx context.Context, cfg ClientConfig) (*client.Client, error)
|
||||
}
|
||||
|
||||
opts = append(opts,
|
||||
client.WithHTTPHeaders(httpHeaders),
|
||||
client.WithVersion(cfg.apiVersion))
|
||||
client.FromEnv,
|
||||
client.WithAPIVersionNegotiation(),
|
||||
client.WithHTTPHeaders(httpHeaders))
|
||||
|
||||
return client.NewClientWithOpts(opts...)
|
||||
}
|
||||
|
||||
@@ -175,9 +175,11 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||
if cfg.HTTP != nil && len(cfg.HTTP.Models) > 0 {
|
||||
rts := make(map[string]*dynamic.Router)
|
||||
|
||||
modelRouterNames := make(map[string][]string)
|
||||
for name, rt := range cfg.HTTP.Routers {
|
||||
// Only root routers can have models applied.
|
||||
if rt.ParentRefs != nil {
|
||||
rts[name] = rt
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -233,7 +235,9 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||
rtName := name
|
||||
if len(eps) > 1 {
|
||||
rtName = epName + "-" + name
|
||||
modelRouterNames[name] = append(modelRouterNames[name], rtName)
|
||||
}
|
||||
|
||||
rts[rtName] = cp
|
||||
} else {
|
||||
router.EntryPoints = append(router.EntryPoints, epName)
|
||||
@@ -243,6 +247,26 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
for _, rt := range rts {
|
||||
if rt.ParentRefs == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var parentRefs []string
|
||||
for _, ref := range rt.ParentRefs {
|
||||
// Only add the initial parent ref if it still exists.
|
||||
if _, ok := rts[ref]; ok {
|
||||
parentRefs = append(parentRefs, ref)
|
||||
}
|
||||
|
||||
if names, ok := modelRouterNames[ref]; ok {
|
||||
parentRefs = append(parentRefs, names...)
|
||||
}
|
||||
}
|
||||
|
||||
rt.ParentRefs = parentRefs
|
||||
}
|
||||
|
||||
cfg.HTTP.Routers = rts
|
||||
}
|
||||
|
||||
|
||||
@@ -810,6 +810,414 @@ func Test_applyModel(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with parentRefs, parent not split",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: make(map[string]*dynamic.Model),
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: make(map[string]*dynamic.Model),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with parentRefs, parent split by model",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"websecure", "web"},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
Middlewares: []string{"test"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"websecure-parent": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
Middlewares: []string{"test"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent", "websecure-parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
Middlewares: []string{"test"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "multiple child routers with parentRefs, parent split by model",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"websecure", "web"},
|
||||
},
|
||||
"child1": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
"child2": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
Middlewares: []string{"auth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"websecure-parent": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
Middlewares: []string{"auth"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child1": {
|
||||
ParentRefs: []string{"parent", "websecure-parent"},
|
||||
},
|
||||
"child2": {
|
||||
ParentRefs: []string{"parent", "websecure-parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
Middlewares: []string{"auth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with parentRefs to non-existing parent",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"child": {
|
||||
ParentRefs: []string{"nonexistent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: make(map[string]*dynamic.Model),
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"child": {
|
||||
ParentRefs: []string{"nonexistent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: make(map[string]*dynamic.Model),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with multiple parentRefs, some split",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent1": {
|
||||
EntryPoints: []string{"websecure", "web"},
|
||||
},
|
||||
"parent2": {
|
||||
EntryPoints: []string{"web"},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent1", "parent2"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"websecure-parent1": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"parent2": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent1", "websecure-parent1", "parent2"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with multiple parentRefs, all split",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent1": {
|
||||
EntryPoints: []string{"websecure", "web"},
|
||||
},
|
||||
"parent2": {
|
||||
EntryPoints: []string{"web"},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent1", "parent2"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"web@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"web-parent1": {
|
||||
EntryPoints: []string{"web"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"websecure-parent1": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"parent2": {
|
||||
EntryPoints: []string{"web"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"websecure-parent1", "web-parent1", "parent2"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"web@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "child router with parentRefs, parent split into three routers",
|
||||
input: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"websecure", "web", "admin"},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
"admin@internal": {
|
||||
Middlewares: []string{"admin-auth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"websecure-parent": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"admin-parent": {
|
||||
EntryPoints: []string{"admin"},
|
||||
Middlewares: []string{"admin-auth"},
|
||||
Observability: &dynamic.RouterObservabilityConfig{
|
||||
AccessLogs: pointer(true),
|
||||
Metrics: pointer(true),
|
||||
Tracing: pointer(true),
|
||||
TraceVerbosity: otypes.MinimalVerbosity,
|
||||
},
|
||||
},
|
||||
"child": {
|
||||
ParentRefs: []string{"parent", "websecure-parent", "admin-parent"},
|
||||
},
|
||||
},
|
||||
Middlewares: make(map[string]*dynamic.Middleware),
|
||||
Services: make(map[string]*dynamic.Service),
|
||||
Models: map[string]*dynamic.Model{
|
||||
"websecure@internal": {
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
"admin@internal": {
|
||||
Middlewares: []string{"admin-auth"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
+8
-28
@@ -32,9 +32,6 @@ type Listener struct {
|
||||
// timeout defines how long to wait on an idle session,
|
||||
// before releasing its related resources.
|
||||
timeout time.Duration
|
||||
|
||||
// readBufferPool is a pool of byte slices for UDP packet reading.
|
||||
readBufferPool sync.Pool
|
||||
}
|
||||
|
||||
// ListenPacketConn creates a new listener from PacketConn.
|
||||
@@ -54,11 +51,6 @@ func ListenPacketConn(packetConn net.PacketConn, timeout time.Duration) (*Listen
|
||||
conns: make(map[string]*Conn),
|
||||
accepting: true,
|
||||
timeout: timeout,
|
||||
readBufferPool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, maxDatagramSize)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
go l.readLoop()
|
||||
@@ -160,26 +152,21 @@ func (l *Listener) readLoop() {
|
||||
for {
|
||||
// Allocating a new buffer for every read avoids
|
||||
// overwriting data in c.msgs in case the next packet is received
|
||||
// before c.msgs is emptied via Read().
|
||||
// Reuses buffers via the readBufferPool sync.Pool.
|
||||
buf := l.readBufferPool.Get().([]byte)
|
||||
// before c.msgs is emptied via Read()
|
||||
buf := make([]byte, maxDatagramSize)
|
||||
|
||||
n, raddr, err := l.pConn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
l.readBufferPool.Put(buf)
|
||||
return
|
||||
}
|
||||
conn, err := l.getConn(raddr)
|
||||
if err != nil {
|
||||
l.readBufferPool.Put(buf)
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
// Receiver must call releaseReadBuffer() when done reading the data.
|
||||
case conn.receiveCh <- buf[:n]:
|
||||
case <-conn.doneCh:
|
||||
l.readBufferPool.Put(buf)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -224,15 +211,15 @@ type Conn struct {
|
||||
listener *Listener
|
||||
rAddr net.Addr
|
||||
|
||||
receiveCh chan []byte // to receive the data from the listener's readLoop.
|
||||
readCh chan []byte // to receive the buffer into which we should Read.
|
||||
sizeCh chan int // to synchronize with the end of a Read.
|
||||
msgs [][]byte // to store data from listener, to be consumed by Reads.
|
||||
receiveCh chan []byte // to receive the data from the listener's readLoop
|
||||
readCh chan []byte // to receive the buffer into which we should Read
|
||||
sizeCh chan int // to synchronize with the end of a Read
|
||||
msgs [][]byte // to store data from listener, to be consumed by Reads
|
||||
|
||||
muActivity sync.RWMutex
|
||||
lastActivity time.Time // the last time the session saw either read or write activity.
|
||||
lastActivity time.Time // the last time the session saw either read or write activity
|
||||
|
||||
timeout time.Duration // for timeouts.
|
||||
timeout time.Duration // for timeouts
|
||||
doneOnce sync.Once
|
||||
doneCh chan struct{}
|
||||
}
|
||||
@@ -267,8 +254,6 @@ func (c *Conn) readLoop() {
|
||||
msg := c.msgs[0]
|
||||
c.msgs = c.msgs[1:]
|
||||
n := copy(cBuf, msg)
|
||||
// Return buffer to sync.Pool once done reading from it.
|
||||
c.listener.readBufferPool.Put(msg)
|
||||
c.sizeCh <- n
|
||||
case msg := <-c.receiveCh:
|
||||
c.msgs = append(c.msgs, msg)
|
||||
@@ -314,11 +299,6 @@ func (c *Conn) Write(p []byte) (n int, err error) {
|
||||
|
||||
func (c *Conn) close() {
|
||||
c.doneOnce.Do(func() {
|
||||
// Release any buffered data before closing.
|
||||
for _, msg := range c.msgs {
|
||||
c.listener.readBufferPool.Put(msg)
|
||||
}
|
||||
c.msgs = nil
|
||||
close(c.doneCh)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||
OutputType = "file"
|
||||
FileName = "traefik_changelog.md"
|
||||
|
||||
# example new bugfix v3.5.6
|
||||
CurrentRef = "v3.5"
|
||||
PreviousRef = "v3.5.5"
|
||||
BaseBranch = "v3.5"
|
||||
FutureCurrentRefName = "v3.5.6"
|
||||
# example new bugfix v3.6.2
|
||||
CurrentRef = "v3.6"
|
||||
PreviousRef = "v3.6.1"
|
||||
BaseBranch = "v3.6"
|
||||
FutureCurrentRefName = "v3.6.2"
|
||||
|
||||
ThresholdPreviousRef = 10
|
||||
ThresholdCurrentRef = 10
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
nodeLinker: node-modules
|
||||
enableScripts: false
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,131 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import useHubUpgradeButton from './use-hub-upgrade-button'
|
||||
|
||||
import { VersionContext } from 'contexts/version'
|
||||
import verifySignature from 'utils/workers/scriptVerification'
|
||||
|
||||
vi.mock('utils/workers/scriptVerification')
|
||||
|
||||
const mockVerifySignature = vi.mocked(verifySignature)
|
||||
|
||||
const createWrapper = (showHubButton: boolean) => {
|
||||
return ({ children }: { children: ReactNode }) => (
|
||||
<VersionContext.Provider value={{ showHubButton, version: '1.0.0' }}>{children}</VersionContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('useHubUpgradeButton Hook', () => {
|
||||
let originalCreateObjectURL: typeof URL.createObjectURL
|
||||
let originalRevokeObjectURL: typeof URL.revokeObjectURL
|
||||
const mockBlobUrl = 'blob:http://localhost:3000/mock-blob-url'
|
||||
|
||||
beforeEach(() => {
|
||||
originalCreateObjectURL = URL.createObjectURL
|
||||
originalRevokeObjectURL = URL.revokeObjectURL
|
||||
URL.createObjectURL = vi.fn(() => mockBlobUrl)
|
||||
URL.revokeObjectURL = vi.fn()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
URL.createObjectURL = originalCreateObjectURL
|
||||
URL.revokeObjectURL = originalRevokeObjectURL
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should not verify script when showHubButton is false', async () => {
|
||||
renderHook(() => useHubUpgradeButton(), {
|
||||
wrapper: createWrapper(false),
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockVerifySignature).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
it('should verify script and create blob URL when showHubButton is true and verification succeeds', async () => {
|
||||
const mockScriptContent = new ArrayBuffer(8)
|
||||
mockVerifySignature.mockResolvedValue({
|
||||
verified: true,
|
||||
scriptContent: mockScriptContent,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useHubUpgradeButton(), {
|
||||
wrapper: createWrapper(true),
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockVerifySignature).toHaveBeenCalledWith(
|
||||
'https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js',
|
||||
'https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js.sig',
|
||||
'MCowBQYDK2VwAyEAY0OZFFE5kSuqYK6/UprTL5RmvQ+8dpPTGMCw1MiO/Gs=',
|
||||
)
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.signatureVerified).toBe(true)
|
||||
})
|
||||
|
||||
expect(result.current.scriptBlobUrl).toBe(mockBlobUrl)
|
||||
expect(URL.createObjectURL).toHaveBeenCalledWith(expect.any(Blob))
|
||||
})
|
||||
|
||||
it('should set signatureVerified to false when verification fails', async () => {
|
||||
mockVerifySignature.mockResolvedValue({
|
||||
verified: false,
|
||||
})
|
||||
|
||||
const { result } = renderHook(() => useHubUpgradeButton(), {
|
||||
wrapper: createWrapper(true),
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockVerifySignature).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.signatureVerified).toBe(false)
|
||||
})
|
||||
|
||||
expect(result.current.scriptBlobUrl).toBeNull()
|
||||
expect(URL.createObjectURL).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle verification errors gracefully', async () => {
|
||||
mockVerifySignature.mockRejectedValue(new Error('Verification failed'))
|
||||
|
||||
const { result } = renderHook(() => useHubUpgradeButton(), {
|
||||
wrapper: createWrapper(true),
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockVerifySignature).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.signatureVerified).toBe(false)
|
||||
})
|
||||
|
||||
expect(result.current.scriptBlobUrl).toBeNull()
|
||||
})
|
||||
|
||||
it('should create blob with correct MIME type', async () => {
|
||||
const mockScriptContent = new ArrayBuffer(8)
|
||||
mockVerifySignature.mockResolvedValue({
|
||||
verified: true,
|
||||
scriptContent: mockScriptContent,
|
||||
})
|
||||
|
||||
renderHook(() => useHubUpgradeButton(), {
|
||||
wrapper: createWrapper(true),
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(URL.createObjectURL).toHaveBeenCalled()
|
||||
})
|
||||
const blobCall = vi.mocked(URL.createObjectURL).mock.calls[0][0] as Blob
|
||||
expect(blobCall).toBeInstanceOf(Blob)
|
||||
expect(blobCall.type).toBe('application/javascript')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
|
||||
import { VersionContext } from 'contexts/version'
|
||||
import verifySignature from 'utils/workers/scriptVerification'
|
||||
|
||||
const HUB_BUTTON_URL = 'https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js'
|
||||
const PUBLIC_KEY = 'MCowBQYDK2VwAyEAY0OZFFE5kSuqYK6/UprTL5RmvQ+8dpPTGMCw1MiO/Gs='
|
||||
|
||||
const useHubUpgradeButton = () => {
|
||||
const [signatureVerified, setSignatureVerified] = useState(false)
|
||||
const [scriptBlobUrl, setScriptBlobUrl] = useState<string | null>(null)
|
||||
const [isCustomElementDefined, setIsCustomElementDefined] = useState(false)
|
||||
|
||||
const { showHubButton } = useContext(VersionContext)
|
||||
|
||||
useEffect(() => {
|
||||
if (showHubButton) {
|
||||
if (customElements.get('hub-button-app')) {
|
||||
setSignatureVerified(true)
|
||||
setIsCustomElementDefined(true)
|
||||
return
|
||||
}
|
||||
|
||||
const verifyAndLoadScript = async () => {
|
||||
try {
|
||||
const { verified, scriptContent: content } = await verifySignature(
|
||||
HUB_BUTTON_URL,
|
||||
`${HUB_BUTTON_URL}.sig`,
|
||||
PUBLIC_KEY,
|
||||
)
|
||||
if (!verified || !content) {
|
||||
setSignatureVerified(false)
|
||||
} else {
|
||||
const blob = new Blob([content], { type: 'application/javascript' })
|
||||
const blobUrl = URL.createObjectURL(blob)
|
||||
|
||||
setScriptBlobUrl(blobUrl)
|
||||
setSignatureVerified(true)
|
||||
}
|
||||
} catch {
|
||||
setSignatureVerified(false)
|
||||
}
|
||||
}
|
||||
|
||||
verifyAndLoadScript()
|
||||
|
||||
return () => {
|
||||
setScriptBlobUrl((currentUrl) => {
|
||||
if (currentUrl) {
|
||||
URL.revokeObjectURL(currentUrl)
|
||||
}
|
||||
return null
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [showHubButton])
|
||||
|
||||
return { signatureVerified, scriptBlobUrl, isCustomElementDefined }
|
||||
}
|
||||
|
||||
export default useHubUpgradeButton
|
||||
@@ -1,9 +1,20 @@
|
||||
import { Flex, Text } from '@traefiklabs/faency'
|
||||
import { AriaTd, Flex, Text } from '@traefiklabs/faency'
|
||||
import { FiAlertTriangle } from 'react-icons/fi'
|
||||
|
||||
export const EmptyPlaceholder = ({ message = 'No data available' }: { message?: string }) => (
|
||||
type EmptyPlaceholderProps = {
|
||||
message?: string
|
||||
}
|
||||
export const EmptyPlaceholder = ({ message = 'No data available' }: EmptyPlaceholderProps) => (
|
||||
<Flex align="center" justify="center" css={{ py: '$5', color: '$primary' }}>
|
||||
<FiAlertTriangle size={16} />
|
||||
<Text css={{ pl: '$2' }}>{message}</Text>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
export const EmptyPlaceholderTd = (props: EmptyPlaceholderProps) => {
|
||||
return (
|
||||
<AriaTd css={{ pointerEvents: 'none' }} fullColSpan>
|
||||
<EmptyPlaceholder {...props} />
|
||||
</AriaTd>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
import { parseMiddlewareType } from 'libs/parsers'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
@@ -79,9 +79,7 @@ export const HttpMiddlewaresRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -16,7 +16,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (protocol = 'http'): RenderRowType => {
|
||||
const HttpRoutersRenderRow = (row) => (
|
||||
@@ -100,9 +100,7 @@ export const HttpRoutersRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
const HttpServicesRenderRow = (row) => (
|
||||
@@ -78,9 +78,7 @@ export const HttpServicesRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { waitFor } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import { PUBLIC_KEY } from './constants'
|
||||
import HubDashboard, { resetCache } from './HubDashboard'
|
||||
import verifySignature from './workers/scriptVerification'
|
||||
|
||||
import { renderWithProviders } from 'utils/test'
|
||||
import verifySignature from 'utils/workers/scriptVerification'
|
||||
|
||||
vi.mock('./workers/scriptVerification', () => ({
|
||||
vi.mock('utils/workers/scriptVerification', () => ({
|
||||
default: vi.fn(),
|
||||
}))
|
||||
|
||||
@@ -34,7 +35,6 @@ describe('HubDashboard demo', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
// Mock URL.createObjectURL
|
||||
mockCreateObjectURL = vi.fn(() => 'blob:mock-url')
|
||||
globalThis.URL.createObjectURL = mockCreateObjectURL
|
||||
})
|
||||
@@ -45,7 +45,6 @@ describe('HubDashboard demo', () => {
|
||||
|
||||
describe('without cache', () => {
|
||||
beforeEach(() => {
|
||||
// Reset cache before each test suites
|
||||
resetCache()
|
||||
})
|
||||
|
||||
@@ -130,6 +129,7 @@ describe('HubDashboard demo', () => {
|
||||
expect(mockVerifyScriptSignature).toHaveBeenCalledWith(
|
||||
'https://assets.traefik.io/hub-ui-demo.js',
|
||||
'https://assets.traefik.io/hub-ui-demo.js.sig',
|
||||
PUBLIC_KEY,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,9 @@ import { useMemo, useEffect, useState } from 'react'
|
||||
import { Helmet } from 'react-helmet-async'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import verifySignature from './workers/scriptVerification'
|
||||
import verifySignature from '../../utils/workers/scriptVerification'
|
||||
|
||||
import { PUBLIC_KEY } from './constants'
|
||||
|
||||
import { SpinnerLoader } from 'components/SpinnerLoader'
|
||||
import { useIsDarkMode } from 'hooks/use-theme'
|
||||
@@ -42,7 +44,7 @@ const HubDashboard = ({ path }: { path: string }) => {
|
||||
setVerificationInProgress(true)
|
||||
|
||||
try {
|
||||
const { verified, scriptContent: content } = await verifySignature(SCRIPT_URL, `${SCRIPT_URL}.sig`)
|
||||
const { verified, scriptContent: content } = await verifySignature(SCRIPT_URL, `${SCRIPT_URL}.sig`, PUBLIC_KEY)
|
||||
|
||||
if (!verified || !content) {
|
||||
setScriptError(true)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const PUBLIC_KEY = 'MCowBQYDK2VwAyEAWMBZ0pMBaL/s8gNXxpAPCIQ8bxjnuz6bQFwGYvjXDfg='
|
||||
@@ -3,9 +3,10 @@ import { ReactNode } from 'react'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import { useHubDemo } from './use-hub-demo'
|
||||
import verifySignature from './workers/scriptVerification'
|
||||
|
||||
vi.mock('./workers/scriptVerification', () => ({
|
||||
import verifySignature from 'utils/workers/scriptVerification'
|
||||
|
||||
vi.mock('utils/workers/scriptVerification', () => ({
|
||||
default: vi.fn(),
|
||||
}))
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { ReactNode, useEffect, useMemo, useState } from 'react'
|
||||
import { RouteObject } from 'react-router-dom'
|
||||
|
||||
import { PUBLIC_KEY } from './constants'
|
||||
|
||||
import HubDashboard from 'pages/hub-demo/HubDashboard'
|
||||
import { ApiIcon, DashboardIcon, GatewayIcon, PortalIcon } from 'pages/hub-demo/icons'
|
||||
import verifySignature from 'pages/hub-demo/workers/scriptVerification'
|
||||
import verifySignature from 'utils/workers/scriptVerification'
|
||||
|
||||
const ROUTES_MANIFEST_URL = 'https://traefik.github.io/hub-ui-demo-app/config/routes.json'
|
||||
|
||||
@@ -20,7 +22,11 @@ const useHubDemoRoutesManifest = (): HubDemo.Manifest | null => {
|
||||
useEffect(() => {
|
||||
const fetchManifest = async () => {
|
||||
try {
|
||||
const { verified, scriptContent } = await verifySignature(ROUTES_MANIFEST_URL, `${ROUTES_MANIFEST_URL}.sig`)
|
||||
const { verified, scriptContent } = await verifySignature(
|
||||
ROUTES_MANIFEST_URL,
|
||||
`${ROUTES_MANIFEST_URL}.sig`,
|
||||
PUBLIC_KEY,
|
||||
)
|
||||
|
||||
if (!verified || !scriptContent) {
|
||||
setManifest(null)
|
||||
|
||||
@@ -14,7 +14,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
import { parseMiddlewareType } from 'libs/parsers'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
@@ -79,9 +79,7 @@ export const TcpMiddlewaresRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -16,7 +16,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
const TcpRoutersRenderRow = (row) => (
|
||||
@@ -96,9 +96,7 @@ export const TcpRoutersRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
const TcpServicesRenderRow = (row) => (
|
||||
@@ -78,9 +78,7 @@ export const TcpServicesRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -15,7 +15,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
const UdpRoutersRenderRow = (row) => (
|
||||
@@ -81,9 +81,7 @@ export const UdpRoutersRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,7 @@ import SortableTh from 'components/tables/SortableTh'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import TooltipText from 'components/TooltipText'
|
||||
import useFetchWithPagination, { pagesResponseInterface, RenderRowType } from 'hooks/use-fetch-with-pagination'
|
||||
import { EmptyPlaceholder } from 'layout/EmptyPlaceholder'
|
||||
import { EmptyPlaceholderTd } from 'layout/EmptyPlaceholder'
|
||||
|
||||
export const makeRowRender = (): RenderRowType => {
|
||||
const UdpServicesRenderRow = (row) => (
|
||||
@@ -78,9 +78,7 @@ export const UdpServicesRender = ({
|
||||
{(isEmpty || !!error) && (
|
||||
<AriaTfoot>
|
||||
<AriaTr>
|
||||
<AriaTd fullColSpan>
|
||||
<EmptyPlaceholder message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTd>
|
||||
<EmptyPlaceholderTd message={error ? 'Failed to fetch data' : 'No data available'} />
|
||||
</AriaTr>
|
||||
</AriaTfoot>
|
||||
)}
|
||||
|
||||
+7
-15
@@ -2,6 +2,8 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import verifySignature from './scriptVerification'
|
||||
|
||||
const SCRIPT_PATH = 'https://example.com/script.js'
|
||||
const MOCK_PUBLIC_KEY = 'MCowBQYDK2VwAyEAWH71OHphISjNK3mizCR/BawiDxc6IXT1vFHpBcxSIA0='
|
||||
class MockWorker {
|
||||
onmessage: ((event: MessageEvent) => void) | null = null
|
||||
onerror: ((error: ErrorEvent) => void) | null = null
|
||||
@@ -46,17 +48,14 @@ describe('verifySignature', () => {
|
||||
})
|
||||
|
||||
it('should return true when verification succeeds', async () => {
|
||||
const scriptPath = 'https://example.com/script.js'
|
||||
const signaturePath = 'https://example.com/script.js.sig'
|
||||
|
||||
const promise = verifySignature(scriptPath, signaturePath)
|
||||
const promise = verifySignature(SCRIPT_PATH, `${SCRIPT_PATH}.sig`, MOCK_PUBLIC_KEY)
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
|
||||
expect(mockWorkerInstance.postMessage).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
scriptUrl: scriptPath,
|
||||
signatureUrl: signaturePath,
|
||||
scriptUrl: SCRIPT_PATH,
|
||||
signatureUrl: `${SCRIPT_PATH}.sig`,
|
||||
requestId: expect.any(String),
|
||||
}),
|
||||
)
|
||||
@@ -76,12 +75,9 @@ describe('verifySignature', () => {
|
||||
})
|
||||
|
||||
it('should return false when verification fails', async () => {
|
||||
const scriptPath = 'https://example.com/script.js'
|
||||
const signaturePath = 'https://example.com/script.js.sig'
|
||||
|
||||
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
const promise = verifySignature(scriptPath, signaturePath)
|
||||
const promise = verifySignature(SCRIPT_PATH, `${SCRIPT_PATH}.sig`, MOCK_PUBLIC_KEY)
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
|
||||
@@ -101,16 +97,12 @@ describe('verifySignature', () => {
|
||||
})
|
||||
|
||||
it('should return false when worker throws an error', async () => {
|
||||
const scriptPath = 'https://example.com/script.js'
|
||||
const signaturePath = 'https://example.com/script.js.sig'
|
||||
|
||||
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
const promise = verifySignature(scriptPath, signaturePath)
|
||||
const promise = verifySignature(SCRIPT_PATH, `${SCRIPT_PATH}.sig`, MOCK_PUBLIC_KEY)
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
|
||||
// Simulate worker onerror event
|
||||
const error = new Error('Worker crashed')
|
||||
mockWorkerInstance.simulateError(error)
|
||||
|
||||
+1
-3
@@ -3,12 +3,10 @@ export interface VerificationResult {
|
||||
scriptContent?: ArrayBuffer
|
||||
}
|
||||
|
||||
const PUBLIC_KEY = 'MCowBQYDK2VwAyEAWMBZ0pMBaL/s8gNXxpAPCIQ8bxjnuz6bQFwGYvjXDfg='
|
||||
|
||||
async function verifySignature(
|
||||
contentPath: string,
|
||||
signaturePath: string,
|
||||
publicKey: string = PUBLIC_KEY,
|
||||
publicKey: string,
|
||||
): Promise<VerificationResult> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = Math.random().toString(36).substring(2)
|
||||
+41
-41
@@ -2871,24 +2871,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@microsoft/api-extractor-model@npm:7.31.3":
|
||||
version: 7.31.3
|
||||
resolution: "@microsoft/api-extractor-model@npm:7.31.3"
|
||||
"@microsoft/api-extractor-model@npm:7.32.0":
|
||||
version: 7.32.0
|
||||
resolution: "@microsoft/api-extractor-model@npm:7.32.0"
|
||||
dependencies:
|
||||
"@microsoft/tsdoc": "npm:~0.15.1"
|
||||
"@microsoft/tsdoc-config": "npm:~0.17.1"
|
||||
"@microsoft/tsdoc": "npm:~0.16.0"
|
||||
"@microsoft/tsdoc-config": "npm:~0.18.0"
|
||||
"@rushstack/node-core-library": "npm:5.18.0"
|
||||
checksum: 10c0/4e4a798c5d92b72fa664932019563f085153cf33f7745f8ea452901348a0021f19c7c3db55e5555b779a78df52d93ec10960349b5bc1ee53bf555e63c0fe1197
|
||||
checksum: 10c0/e6d9c54a457c66dec53765522f411c8ca5d2bb8c51559b9f952fdd7bb88b10efe035a8dbdf8b672644c136d75a65f3446b3b18938fa50c0a766f83111cbda5eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@microsoft/api-extractor@npm:^7.50.1":
|
||||
version: 7.54.0
|
||||
resolution: "@microsoft/api-extractor@npm:7.54.0"
|
||||
version: 7.55.0
|
||||
resolution: "@microsoft/api-extractor@npm:7.55.0"
|
||||
dependencies:
|
||||
"@microsoft/api-extractor-model": "npm:7.31.3"
|
||||
"@microsoft/tsdoc": "npm:~0.15.1"
|
||||
"@microsoft/tsdoc-config": "npm:~0.17.1"
|
||||
"@microsoft/api-extractor-model": "npm:7.32.0"
|
||||
"@microsoft/tsdoc": "npm:~0.16.0"
|
||||
"@microsoft/tsdoc-config": "npm:~0.18.0"
|
||||
"@rushstack/node-core-library": "npm:5.18.0"
|
||||
"@rushstack/rig-package": "npm:0.6.0"
|
||||
"@rushstack/terminal": "npm:0.19.3"
|
||||
@@ -2902,26 +2902,26 @@ __metadata:
|
||||
typescript: "npm:5.8.2"
|
||||
bin:
|
||||
api-extractor: bin/api-extractor
|
||||
checksum: 10c0/e4708ac5edc3bb32988b632cc75e6f5e5b3afe7772c7229974db91f731d6b8d3c786c406d5437bfce893b78c6f23c64b084db52952a7d35294e2525171a465ee
|
||||
checksum: 10c0/3211981b7aaf6ca7a36fe33dc9cab5014dc753c0c75d09ace46bef07db947a433ca9daecc843ea13b29fe7527ea3d357c7bd5051fedf10ae3b3db31d2a5de71f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@microsoft/tsdoc-config@npm:~0.17.1":
|
||||
version: 0.17.1
|
||||
resolution: "@microsoft/tsdoc-config@npm:0.17.1"
|
||||
"@microsoft/tsdoc-config@npm:~0.18.0":
|
||||
version: 0.18.0
|
||||
resolution: "@microsoft/tsdoc-config@npm:0.18.0"
|
||||
dependencies:
|
||||
"@microsoft/tsdoc": "npm:0.15.1"
|
||||
"@microsoft/tsdoc": "npm:0.16.0"
|
||||
ajv: "npm:~8.12.0"
|
||||
jju: "npm:~1.4.0"
|
||||
resolve: "npm:~1.22.2"
|
||||
checksum: 10c0/a686355796f492f27af17e2a17d615221309caf4d9f9047a5a8f17f8625c467c4c81e2a7923ddafd71b892631d5e5013c4b8cc49c5867d3cc1d260fd90c1413d
|
||||
checksum: 10c0/6e2c3bfde3e5fa4c0360127c86fe016dcf1b09d0091d767c06ce916284d3f6aeea3617a33b855c5bb2615ab0f2840eeebd4c7f4a1f879f951828d213bf306cfd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@microsoft/tsdoc@npm:0.15.1, @microsoft/tsdoc@npm:~0.15.1":
|
||||
version: 0.15.1
|
||||
resolution: "@microsoft/tsdoc@npm:0.15.1"
|
||||
checksum: 10c0/09948691fac56c45a0d1920de478d66a30371a325bd81addc92eea5654d95106ce173c440fea1a1bd5bb95b3a544b6d4def7bb0b5a846c05d043575d8369a20c
|
||||
"@microsoft/tsdoc@npm:0.16.0, @microsoft/tsdoc@npm:~0.16.0":
|
||||
version: 0.16.0
|
||||
resolution: "@microsoft/tsdoc@npm:0.16.0"
|
||||
checksum: 10c0/8883bb0ed22753af7360e9222687fda4eb448f0a574ea34b4596c11e320148b3ae0d24e00f8923df8ba7bc62a46a6f53b9343243a348640d923dfd55d52cd6bb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6524,26 +6524,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-core@npm:3.5.23":
|
||||
version: 3.5.23
|
||||
resolution: "@vue/compiler-core@npm:3.5.23"
|
||||
"@vue/compiler-core@npm:3.5.24":
|
||||
version: 3.5.24
|
||||
resolution: "@vue/compiler-core@npm:3.5.24"
|
||||
dependencies:
|
||||
"@babel/parser": "npm:^7.28.5"
|
||||
"@vue/shared": "npm:3.5.23"
|
||||
"@vue/shared": "npm:3.5.24"
|
||||
entities: "npm:^4.5.0"
|
||||
estree-walker: "npm:^2.0.2"
|
||||
source-map-js: "npm:^1.2.1"
|
||||
checksum: 10c0/195c57b2eb8c6948bf3b1b3f65c2a5a9bf9e252376bcd22bd9b5e1787c4254abc4bffab5f15902c7820f5e607b26d44578cddeb39605ece37b611703c2d6152b
|
||||
checksum: 10c0/d5b1421c0c0cfdff6b6ae2ef3d59b5901f0fec8ad2fa153f5ae1ec8487b898c92766353c661f68b892580ab0eacbc493632c946af8141045d6e76d67797b8a84
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-dom@npm:^3.5.0":
|
||||
version: 3.5.23
|
||||
resolution: "@vue/compiler-dom@npm:3.5.23"
|
||||
version: 3.5.24
|
||||
resolution: "@vue/compiler-dom@npm:3.5.24"
|
||||
dependencies:
|
||||
"@vue/compiler-core": "npm:3.5.23"
|
||||
"@vue/shared": "npm:3.5.23"
|
||||
checksum: 10c0/fb925b2d64de40c1b39852f5fd26fdec3238f8381ccc2b30a1bef372ef894fff4e6f0231f8a135a02d6a5c8b8254dc7018bcd136a689579a72a3a0e1ff211a89
|
||||
"@vue/compiler-core": "npm:3.5.24"
|
||||
"@vue/shared": "npm:3.5.24"
|
||||
checksum: 10c0/d49cb715f2e1cb2272ede2e41901282fb3f6fbdf489c8aa737e60c68e21216e07b72942695a80430fee8f11e5933e36fc90615b146b189cac925bf32f2727c95
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6578,10 +6578,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/shared@npm:3.5.23, @vue/shared@npm:^3.5.0":
|
||||
version: 3.5.23
|
||||
resolution: "@vue/shared@npm:3.5.23"
|
||||
checksum: 10c0/0f051ea60a756520b0b0af3d5058587b47f1942476c7f2cee6f78589c97c246acabdea11c73e2f84f13ecfb36c1160aacecca37694144326ebec8c108103bb89
|
||||
"@vue/shared@npm:3.5.24, @vue/shared@npm:^3.5.0":
|
||||
version: 3.5.24
|
||||
resolution: "@vue/shared@npm:3.5.24"
|
||||
checksum: 10c0/4fd5665539fa5be3d12280c1921a8db3a707115fef54d22d83ce347ea06e3b1089dfe07292e0c46bbebf23553c7c1ec98010972ebccf10532db82422801288ff
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10099,9 +10099,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"exsolve@npm:^1.0.7":
|
||||
version: 1.0.7
|
||||
resolution: "exsolve@npm:1.0.7"
|
||||
checksum: 10c0/4479369d0bd84bb7e0b4f5d9bc18d26a89b6dbbbccd73f9d383d14892ef78ddbe159e01781055342f83dc00ebe90044036daf17ddf55cc21e2cac6609aa15631
|
||||
version: 1.0.8
|
||||
resolution: "exsolve@npm:1.0.8"
|
||||
checksum: 10c0/65e44ae05bd4a4a5d87cfdbbd6b8f24389282cf9f85fa5feb17ca87ad3f354877e6af4cd99e02fc29044174891f82d1d68c77f69234410eb8f163530e6278c67
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -18670,8 +18670,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0, vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0":
|
||||
version: 7.2.1
|
||||
resolution: "vite@npm:7.2.1"
|
||||
version: 7.2.2
|
||||
resolution: "vite@npm:7.2.2"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.25.0"
|
||||
fdir: "npm:^6.5.0"
|
||||
@@ -18720,7 +18720,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/25fbcfc67b1598fa6152f3ed0a7355144a2ac203859ad3b6a2e466b0930ec1081c19cc6f0d83104897517ecf30c0aac3e4a50c4e5e2980d3659decb1d9e41a28
|
||||
checksum: 10c0/9c76ee441f8dbec645ddaecc28d1f9cf35670ffa91cff69af7b1d5081545331603f0b1289d437b2fa8dc43cdc77b4d96b5bd9c9aed66310f490cb1a06f9c814c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user