mirror of
https://github.com/containous/traefik.git
synced 2025-03-19 18:50:12 +03:00
Merge branch v3.3 into master
This commit is contained in:
commit
30fe11eccf
2
.github/workflows/validate.yaml
vendored
2
.github/workflows/validate.yaml
vendored
@ -7,7 +7,7 @@ on:
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
GOLANGCI_LINT_VERSION: v1.63.3
|
||||
GOLANGCI_LINT_VERSION: v1.64.2
|
||||
MISSPELL_VERSION: v0.6.0
|
||||
|
||||
jobs:
|
||||
|
@ -1,5 +1,6 @@
|
||||
run:
|
||||
timeout: 10m
|
||||
relative-path-mode: cfg
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
@ -165,6 +166,7 @@ linters-settings:
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- tenv # Deprecated
|
||||
- sqlclosecheck # not relevant (SQL)
|
||||
- rowserrcheck # not relevant (SQL)
|
||||
- cyclop # duplicate of gocyclo
|
||||
@ -201,7 +203,6 @@ linters:
|
||||
- maintidx # kind of duplicate of gocyclo
|
||||
- nonamedreturns # Too strict
|
||||
- gosmopolitan # not relevant
|
||||
- exportloopref # Not relevant since go1.22
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -1,3 +1,33 @@
|
||||
## [v3.3.4](https://github.com/traefik/traefik/tree/v3.3.4) (2025-02-25)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.3.3...v3.3.4)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[fastproxy]** Bump github.com/valyala/fasthttp to v1.58.0 ([#11526](https://github.com/traefik/traefik/pull/11526) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[fastproxy]** Add WebSocket headers if they are present in the request ([#11522](https://github.com/traefik/traefik/pull/11522) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[fastproxy]** Chunked responses does not have a Content-Length header ([#11514](https://github.com/traefik/traefik/pull/11514) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[metrics,otel]** Change request duration metric unit from millisecond to second ([#11523](https://github.com/traefik/traefik/pull/11523) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[sticky-session]** Fix double hash in sticky cookie ([#11518](https://github.com/traefik/traefik/pull/11518) by [juliens](https://github.com/juliens))
|
||||
- **[tracing]** Use ResourceAttributes instead of GlobalAttributes ([#11515](https://github.com/traefik/traefik/pull/11515) by [bruno-de-queiroz](https://github.com/bruno-de-queiroz))
|
||||
- **[tracing]** Fix panic when calling Tracer ([#11479](https://github.com/traefik/traefik/pull/11479) by [basgys](https://github.com/basgys))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Update ACME provider configuration options ([#11564](https://github.com/traefik/traefik/pull/11564) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- **[acme]** Fix incorrect grammar in ACME documentation ([#11553](https://github.com/traefik/traefik/pull/11553) by [Peter-Maguire](https://github.com/Peter-Maguire))
|
||||
- **[metrics,tracing,accesslogs]** Add missing options in entrypoints page ([#11524](https://github.com/traefik/traefik/pull/11524) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||
- **[tracing]** Replace globalAttributes with resourceAttributes in tracing reference ([#11531](https://github.com/traefik/traefik/pull/11531) by [rtribotte](https://github.com/rtribotte))
|
||||
|
||||
**Misc:**
|
||||
- Merge branch v2.11 into v3.3 ([#11567](https://github.com/traefik/traefik/pull/11567) by [kevinpollet](https://github.com/kevinpollet))
|
||||
|
||||
# [v2.11.21](https://github.com/traefik/traefik/tree/v2.11.21) (2025-02-24)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.20...v2.11.21)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.22.2 ([#11537](https://github.com/traefik/traefik/pull/11537) by [ldez](https://github.com/ldez))
|
||||
- **[cli]** Bump github.com/traefik/paerser to v0.2.2 ([#11530](https://github.com/traefik/traefik/pull/11530) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[middleware]** Enable the retry middleware in the proxy ([#11536](https://github.com/traefik/traefik/pull/11536) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[middleware]** Retry should send headers on Write ([#11534](https://github.com/traefik/traefik/pull/11534) by [kevinpollet](https://github.com/kevinpollet))
|
||||
|
||||
## [v3.3.3](https://github.com/traefik/traefik/tree/v3.3.3) (2025-01-31)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v3.3.2...v3.3.3)
|
||||
|
||||
|
2
Makefile
2
Makefile
@ -175,7 +175,7 @@ docs-pull-images:
|
||||
.PHONY: generate-crd
|
||||
#? generate-crd: Generate CRD clientset and CRD manifests
|
||||
generate-crd:
|
||||
@$(CURDIR)/script/code-gen-docker.sh
|
||||
@$(CURDIR)/script/code-gen.sh
|
||||
|
||||
.PHONY: generate-genconf
|
||||
#? generate-genconf: Generate code from dynamic configuration github.com/traefik/genconf
|
||||
|
@ -59,7 +59,7 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
|
||||
|
||||
- Continuously updates its configuration (No restarts!)
|
||||
- Supports multiple load balancing algorithms
|
||||
- Provides HTTPS to your microservices by leveraging [Let's Encrypt](https://letsencrypt.org) (wildcard certificates support)
|
||||
- Provides HTTPS to your microservices by leveraging [Let's Encrypt](https://letsencrypt.org) (wildcard certificates support)
|
||||
- Circuit breakers, retry
|
||||
- See the magic through its clean web UI
|
||||
- WebSocket, HTTP/2, gRPC ready
|
||||
|
@ -143,21 +143,6 @@ To take into account the new certificate contents, the update of the dynamic con
|
||||
One way to achieve that, is to trigger a file notification,
|
||||
for example, by using the `touch` command on the configuration file.
|
||||
|
||||
## What Are the Forwarded Headers When Proxying HTTP Requests?
|
||||
|
||||
By default, the following headers are automatically added when proxying requests:
|
||||
|
||||
| Property | HTTP Header |
|
||||
|---------------------------|----------------------------|
|
||||
| Client's IP | X-Forwarded-For, X-Real-Ip |
|
||||
| Host | X-Forwarded-Host |
|
||||
| Port | X-Forwarded-Port |
|
||||
| Protocol | X-Forwarded-Proto |
|
||||
| Proxy Server's Hostname | X-Forwarded-Server |
|
||||
|
||||
For more details,
|
||||
please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation.
|
||||
|
||||
## How Traefik is Storing and Serving TLS Certificates?
|
||||
|
||||
### Storing TLS Certificates
|
||||
|
@ -316,7 +316,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
|
||||
|
||||
| Provider Name | Provider Code | Environment Variables | |
|
||||
|------------------------------------------------------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) |
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH`, `ACME_DNS_STORAGE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) |
|
||||
| [all-inkl](https://all-inkl.com) | `allinkl` | `ALL_INKL_LOGIN`, `ALL_INKL_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/allinkl) |
|
||||
| [ArvanCloud](https://www.arvancloud.ir/en) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) |
|
||||
@ -397,6 +397,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
|
||||
| [Metaname](https://metaname.net) | `metaname` | `METANAME_ACCOUNT_REFERENCE`, `METANAME_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/metaname) |
|
||||
| [mijn.host](https://mijn.host/) | `mijnhost` | `MIJNHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/mijnhost) |
|
||||
| [Mittwald](https://www.mittwald.de) | `mittwald` | `MITTWALD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/mittwald) |
|
||||
| [myaddr.{tools,dev,io}](https://myaddr.tools/) | `myaddr` | `MYADDR_PRIVATE_KEYS_MAPPING` | [Additional configuration](https://go-acme.github.io/lego/dns/myaddr) |
|
||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
|
||||
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
|
||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
|
||||
@ -434,6 +435,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
|
||||
| [Shellrent](https://www.shellrent.com) | `shellrent` | `SHELLRENT_USERNAME`, `SHELLRENT_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/shellrent) |
|
||||
| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) |
|
||||
| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) |
|
||||
| [Spaceship](https://spaceship.com) | `spaceship` | `SPACESHIP_API_KEY`, `SPACESHIP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/spaceship) |
|
||||
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/stackpath) |
|
||||
| [Technitium](https://technitium.com) | `technitium` | `TECHNITIUM_SERVER_BASE_URL`, `TECHNITIUM_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/technitium) |
|
||||
| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) |
|
||||
@ -538,7 +540,7 @@ certificatesResolvers:
|
||||
|
||||
Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready.
|
||||
|
||||
Please note that disabling checks can prevent the challenge to succeed.
|
||||
Please note that disabling checks can prevent the challenge from succeeding.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
|
@ -179,9 +179,15 @@ http:
|
||||
_Optional, Default=1024_
|
||||
|
||||
`minResponseBodyBytes` specifies the minimum amount of bytes a response body must have to be compressed.
|
||||
|
||||
Responses smaller than the specified values will not be compressed.
|
||||
|
||||
!!! tip "Streaming"
|
||||
|
||||
When data is sent to the client on flush, the `minResponseBodyBytes` configuration is ignored and the data is compressed.
|
||||
This is particularly the case when data is streamed to the client when using `Transfer-encoding: chunked` response.
|
||||
|
||||
When chunked data is sent to the client on flush, it will be compressed by default even if the received data has not reached
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.minresponsebodybytes=1200"
|
||||
|
@ -325,7 +325,8 @@ _Optional_
|
||||
If `region` is not provided, it is resolved from the EC2 metadata endpoint for EC2 tasks.
|
||||
In a FARGATE context it is resolved from the `AWS_REGION` environment variable.
|
||||
|
||||
If `accessKeyID` and `secretAccessKey` are not provided, credentials are resolved in the following order:
|
||||
If `accessKeyID` and `secretAccessKey` are not provided, credentials are resolved in the order specified by the
|
||||
[default credential chain of AWS SDK for Go V2](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials):
|
||||
|
||||
- Using the environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
|
||||
- Using shared credentials, determined by `AWS_PROFILE` and `AWS_SHARED_CREDENTIALS_FILE`, defaults to `default` and `~/.aws/credentials`.
|
||||
|
@ -10,6 +10,12 @@ A Story of KV store & Containers
|
||||
|
||||
Store your configuration in Redis and let Traefik do the rest!
|
||||
|
||||
!!! tip "Dynamic configuration updates"
|
||||
|
||||
Dynamic configuration updates require Redis [keyspace notifications](https://redis.io/docs/latest/develop/use/keyspace-notifications) to be enabled.
|
||||
Cloud-managed Redis services (e.g., GCP Memorystore, AWS ElastiCache) may disable this by default due to CPU performance issues.
|
||||
For more information, see the [Redis](https://redis.io/docs/latest/develop/use/keyspace-notifications/) documentation or refer to your cloud provider's documentation for specific configuration steps.
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
See the dedicated section in [routing](../routing/providers/kv.md).
|
||||
|
@ -3,7 +3,7 @@ title: "Traefik Kubernetes Ingress Documentation"
|
||||
description: "Understand the requirements, routing configuration, and how to set up Traefik Proxy as your Kubernetes Ingress Controller. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Traefik & Kubernetes
|
||||
# Traefik & Kubernetes
|
||||
|
||||
The Traefik Kubernetes Ingress 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.
|
||||
|
@ -79,15 +79,17 @@ ACME certificate resolvers have the following configuration options:
|
||||
| `acme.caServer` | CA server to use. | https://acme-v02.api.letsencrypt.org/directory | No |
|
||||
| `acme.preferredChain` | Preferred chain to use. If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used. | "" | No |
|
||||
| `acme.keyType` | KeyType to use. | "RSA4096" | No |
|
||||
| `acme.eab` | Enable external account binding.| "" | No |
|
||||
| `acme.eab.kid` | Key identifier from External CA. | | No |
|
||||
| `acme.eab` | Enable external account binding.| | No |
|
||||
| `acme.eab.kid` | Key identifier from External CA. | "" | No |
|
||||
| `acme.eab.hmacEncoded` | HMAC key from External CA, should be in Base64 URL Encoding without padding format. | "" | No |
|
||||
| `acme.certificatesDuration` | The certificates' duration in hours, exclusively used to determine renewal dates. | 2160 | No |
|
||||
| `acme.dnsChallenge` | Enable DNS-01 challenge. More information [here](#dnschallenge). | - | No |
|
||||
| `acme.dnsChallenge.provider` | DNS provider to use. | | No |
|
||||
| `acme.dnsChallenge.delayBeforeCheck` | By default, the provider will verify the TXT DNS challenge record before letting ACME verify. If `delayBeforeCheck` is greater than zero, this check is delayed for the configured duration in seconds. Useful if internal networks block external DNS queries. | | No |
|
||||
| `acme.dnsChallenge.resolvers` | DNS servers to resolve the FQDN authority. | | No |
|
||||
| `acme.dnsChallenge.disablePropagationCheck` | Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. | | No |
|
||||
| `acme.dnsChallenge.provider` | DNS provider to use. | "" | No |
|
||||
| `acme.dnsChallenge.resolvers` | DNS servers to resolve the FQDN authority. | [] | No |
|
||||
| `acme.dnsChallenge.propagation.delayBeforeChecks` | By default, the provider will verify the TXT DNS challenge record before letting ACME verify. If `delayBeforeCheck` is greater than zero, this check is delayed for the configured duration in seconds. This is Useful if internal networks block external DNS queries. | 0s | No |
|
||||
| `acme.dnsChallenge.propagation.disableChecks` | Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready. Please note that disabling checks can prevent the challenge from succeeding. | false | No |
|
||||
| `acme.dnsChallenge.propagation.requireAllRNS` | Enables the challenge TXT record to be propagated to all recursive nameservers. If you have disabled authoritative nameservers checks (with `propagation.disableANSChecks`), it is recommended to check all recursive nameservers instead. | false | No |
|
||||
| `acme.dnsChallenge.propagation.disableANSChecks` | Disables the challenge TXT record propagation checks against authoritative nameservers. This option will skip the propagation check against the nameservers of the authority (SOA). It should be used only if the nameservers of the authority are not reachable. | false | No |
|
||||
| `acme.httpChallenge` | Enable HTTP-01 challenge. More information [here](#httpchallenge). | | No |
|
||||
| `acme.httpChallenge.entryPoint` | EntryPoint to use for the HTTP-01 challenges. Must be reachable by Let's Encrypt through port 80 | "" | Yes |
|
||||
| `acme.tlsChallenge` | Enable TLS-ALPN-01 challenge. Traefik must be reachable by Let's Encrypt through port 443. More information [here](#tlschallenge). | - | No |
|
||||
|
@ -0,0 +1,187 @@
|
||||
---
|
||||
title: 'Providing Dynamic Configuration to Traefik'
|
||||
description: 'Learn about the different methods for providing dynamic configuration to Traefik. Read the technical documentation.'
|
||||
---
|
||||
|
||||
# Providing Dynamic (Routing) Configuration to Traefik
|
||||
|
||||
Dynamic configuration—now also known as routing configuration—defines how Traefik routes incoming requests to the correct services. This is distinct from install configuration (formerly known as static configuration), which sets up Traefik’s core components and providers.
|
||||
|
||||
Depending on your environment and preferences, there are several ways to supply this routing configuration:
|
||||
|
||||
- File or Structured Provider: Use TOML or YAML files.
|
||||
- Docker and ECS Providers: Use container labels.
|
||||
- Kubernetes Providers: Use annotations.
|
||||
- KV Providers : Use key-value pairs.
|
||||
- Other Providers (Consul, Nomad, etc.) : Use tags.
|
||||
|
||||
## Using the File Provider
|
||||
|
||||
The File provider allows you to define routing configuration in static files using either TOML or YAML syntax. This method is ideal for environments where services cannot be automatically discovered or when you prefer to manage configurations manually.
|
||||
|
||||
### Enabling the File Provider
|
||||
|
||||
To enable the File provider, add the following to your Traefik install configuration:
|
||||
|
||||
```yaml tab="YAML"
|
||||
providers:
|
||||
file:
|
||||
directory: "/path/to/dynamic/conf"
|
||||
```
|
||||
|
||||
```toml tab="TOML"
|
||||
[providers.file]
|
||||
directory = "/path/to/dynamic/conf"
|
||||
```
|
||||
|
||||
???+ example "Example using the file provider to declare routers & services"
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
routers:
|
||||
my-router:
|
||||
rule: "Host(`example.com`)"
|
||||
service: my-service
|
||||
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://localhost:8080"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http]
|
||||
[http.routers]
|
||||
[http.routers.my-router]
|
||||
rule = "Host(`example.com`)"
|
||||
service = "my-service"
|
||||
|
||||
[http.services]
|
||||
[http.services.my-service.loadBalancer]
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://localhost:8080"
|
||||
```
|
||||
|
||||
## Using Labels With Docker and ECS
|
||||
|
||||
When using Docker or Amazon ECS, you can define routing configuration using container labels. This method allows Traefik to automatically discover services and apply configurations without the need for additional files.
|
||||
|
||||
???+ example "Example with Docker"
|
||||
|
||||
When deploying a Docker container, you can specify labels to define routing rules and services:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
my-service:
|
||||
image: my-image
|
||||
labels:
|
||||
- "traefik.http.routers.my-router.rule=Host(`example.com`)"
|
||||
- "traefik.http.services.my-service.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
???+ example "Example with ECS"
|
||||
|
||||
In ECS, you can use task definition labels to achieve the same effect:
|
||||
|
||||
```yaml
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "my-service",
|
||||
"image": "my-image",
|
||||
"dockerLabels": {
|
||||
"traefik.http.routers.my-router.rule": "Host(`example.com`)",
|
||||
"traefik.http.services.my-service.loadbalancer.server.port": "80"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Using Kubernetes Providers
|
||||
|
||||
For Kubernetes providers, you can configure Traefik using the native Ingress or custom resources (like IngressRoute). Annotations in your Ingress or IngressRoute definition allow you to define routing rules and middleware settings. For example:
|
||||
|
||||
???+ example "Example with Kubernetes"
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: apps
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.priority: "42"
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
traefik.ingress.kubernetes.io/router.tls.options: apps-opt@kubernetescrd
|
||||
spec:
|
||||
rules:
|
||||
- host: my-domain.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
namespace: apps
|
||||
port:
|
||||
number: 80
|
||||
tls:
|
||||
- secretName: supersecret
|
||||
```
|
||||
|
||||
## Using Key-Value Pairs With KV Providers
|
||||
|
||||
For [KV providers](./other-providers/kv.md) you can configure Traefik with key-value pairs.
|
||||
|
||||
???+ example "Examples"
|
||||
|
||||
```bash tab="etcd"
|
||||
# Set a router rule
|
||||
etcdctl put /traefik/http/routers/my-router/rule "Host(`example.com`)"
|
||||
# Define the service associated with the router
|
||||
etcdctl put /traefik/http/routers/my-router/service "my-service"
|
||||
# Set the backend server URL for the service
|
||||
etcdctl put /traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080"
|
||||
```
|
||||
|
||||
```bash tab="Redis"
|
||||
# Set a router rule
|
||||
redis-cli set traefik/http/routers/my-router/rule "Host(`example.com`)"
|
||||
# Define the service associated with the router
|
||||
redis-cli set traefik/http/routers/my-router/service "my-service"
|
||||
# Set the backend server URL for the service
|
||||
redis-cli set traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080"
|
||||
```
|
||||
|
||||
```bash tab="ZooKeeper"
|
||||
# Set a router rule
|
||||
create /traefik/http/routers/my-router/rule "Host(`example.com`)"
|
||||
# Define the service associated with the router
|
||||
create /traefik/http/routers/my-router/service "my-service"
|
||||
# Set the backend server URL for the service
|
||||
create /traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080"
|
||||
```
|
||||
|
||||
## Using Tags With Other Providers
|
||||
|
||||
For providers that do not support labels, such as Consul & Nomad, you can use tags to provide routing configuration.
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```json tab="Consul / Nomad"
|
||||
{
|
||||
"Name": "my-service",
|
||||
"Tags": [
|
||||
"traefik.http.routers.my-router.rule=Host(`example.com`)",
|
||||
"traefik.http.services.my-service.loadbalancer.server.port=80"
|
||||
],
|
||||
"Address": "localhost",
|
||||
"Port": 8080
|
||||
}
|
||||
```
|
@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "ServersTransport"
|
||||
description: "ServersTransport allows configuring the connection between Traefik and the HTTP servers."
|
||||
---
|
||||
|
||||
ServersTransport allows you to configure the transport between Traefik and your HTTP servers.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Declare the serversTransport:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
serversTransports:
|
||||
mytransport:
|
||||
serverName: "myhost"
|
||||
certificates:
|
||||
- "/path/to/cert1.pem"
|
||||
- "/path/to/cert2.pem"
|
||||
insecureSkipVerify: true
|
||||
rootcas:
|
||||
- "/path/to/rootca1.pem"
|
||||
- "/path/to/rootca2.pem"
|
||||
maxIdleConnsPerHost: 100
|
||||
disableHTTP2: true
|
||||
peerCertURI: "spiffe://example.org/peer"
|
||||
forwardingTimeouts:
|
||||
dialTimeout: "30s"
|
||||
responseHeaderTimeout: "10s"
|
||||
idleConnTimeout: "60s"
|
||||
readIdleTimeout: "5s"
|
||||
pingTimeout: "15s"
|
||||
spiffe:
|
||||
ids:
|
||||
- "spiffe://example.org/id1"
|
||||
- "spiffe://example.org/id2"
|
||||
trustDomain: "example.org"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.serversTransports.mytransport]
|
||||
serverName = "myhost"
|
||||
certificates = ["/path/to/cert1.pem", "/path/to/cert2.pem"]
|
||||
insecureSkipVerify = true
|
||||
rootcas = ["/path/to/rootca1.pem", "/path/to/rootca2.pem"]
|
||||
maxIdleConnsPerHost = 100
|
||||
disableHTTP2 = true
|
||||
peerCertURI = "spiffe://example.org/peer"
|
||||
|
||||
[http.serversTransports.mytransport.forwardingTimeouts]
|
||||
dialTimeout = "30s"
|
||||
responseHeaderTimeout = "10s"
|
||||
idleConnTimeout = "60s"
|
||||
readIdleTimeout = "5s"
|
||||
pingTimeout = "15s"
|
||||
|
||||
[http.serversTransports.mytransport.spiffe]
|
||||
ids = ["spiffe://example.org/id1", "spiffe://example.org/id2"]
|
||||
trustDomain = "example.org"
|
||||
```
|
||||
|
||||
Attach the serversTransport to a service:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
Service01:
|
||||
loadBalancer:
|
||||
serversTransport: mytransport
|
||||
```
|
||||
|
||||
```toml tab="Structured(TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.Service01]
|
||||
[http.services.Service01.loadBalancer]
|
||||
serversTransport = "mytransport"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.services.Service01.loadBalancer.serversTransport=mytransport"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.services.Service01.loadBalancer.serversTransport=mytransport"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `serverName` | Configures the server name that will be used as the SNI. | "" | No |
|
||||
| `certificates` | Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. | [] | No |
|
||||
| `insecureSkipVerify` | Controls whether the server's certificate chain and host name is verified. | false | No |
|
||||
| `rootcas` | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | [] | No |
|
||||
| `maxIdleConnsPerHost` | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
|
||||
| `disableHTTP2` | Disables HTTP/2 for connections with servers. | false | No |
|
||||
| `peerCertURI` | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
|
||||
| `forwardingTimeouts.dialTimeout` | Amount of time to wait until a connection to a server can be established.<br />0 = no timeout | 30s | No |
|
||||
| `forwardingTimeouts.responseHeaderTimeout` | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />0 = no timeout | 0s | No |
|
||||
| `forwardingTimeouts.idleConnTimeout` | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />0 = no timeout | 90s | No |
|
||||
| `forwardingTimeouts.readIdleTimeout` | Defines the timeout after which a health check using ping frame will be carried out if no frame is received on the HTTP/2 connection. | 0s | No |
|
||||
| `forwardingTimeouts.pingTimeout` | Defines the timeout after which the HTTP/2 connection will be closed if a response to ping is not received. | 15s | No |
|
||||
| `spiffe.ids` | Defines the allowed SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | [] | No |
|
||||
| `spiffe.trustDomain` | Defines the SPIFFE trust domain. | "" | No |
|
@ -0,0 +1,471 @@
|
||||
---
|
||||
title: "Traefik HTTP Services Documentation"
|
||||
description: "A service is in charge of connecting incoming requests to the Servers that can handle them. Read the technical documentation."
|
||||
---
|
||||
|
||||
## Service Load Balancer
|
||||
|
||||
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||
|
||||
Each service has a load-balancer, even if there is only one server to forward traffic to.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
weight: 2
|
||||
preservePath: true
|
||||
sticky:
|
||||
cookie:
|
||||
name: "sticky-cookie"
|
||||
healthcheck:
|
||||
path: "/health"
|
||||
interval: "10s"
|
||||
timeout: "3s"
|
||||
passHostHeader: true
|
||||
serversTransport: "customTransport@file"
|
||||
responseForwarding:
|
||||
flushInterval: "150ms"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.services]
|
||||
[http.services.my-service.loadBalancer]
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||
name = "sticky-cookie"
|
||||
|
||||
[http.services.my-service.loadBalancer.healthcheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
|
||||
passHostHeader = true
|
||||
serversTransport = "customTransport@file"
|
||||
|
||||
[http.services.my-service.loadBalancer.responseForwarding]
|
||||
flushInterval = "150ms"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.services.my-service.loadBalancer.servers[0].url=http://private-ip-server-1/"
|
||||
- "traefik.http.services.my-service.loadBalancer.servers[0].weight=2"
|
||||
- "traefik.http.services.my-service.loadBalancer.servers[0].preservePath=true"
|
||||
- "traefik.http.services.my-service.loadBalancer.sticky.cookie.name=sticky-cookie"
|
||||
- "traefik.http.services.my-service.loadBalancer.healthcheck.path=/health"
|
||||
- "traefik.http.services.my-service.loadBalancer.healthcheck.interval=10s"
|
||||
- "traefik.http.services.my-service.loadBalancer.healthcheck.timeout=3s"
|
||||
- "traefik.http.services.my-service.loadBalancer.passHostHeader=true"
|
||||
- "traefik.http.services.my-service.loadBalancer.serversTransport=customTransport@file"
|
||||
- "traefik.http.services.my-service.loadBalancer.responseForwarding.flushInterval=150ms"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.services.my-service.loadBalancer.servers[0].url=http://private-ip-server-1/",
|
||||
"traefik.http.services.my-service.loadBalancer.servers[0].weight=2",
|
||||
"traefik.http.services.my-service.loadBalancer.servers[0].preservePath=true",
|
||||
"traefik.http.services.my-service.loadBalancer.sticky.cookie.name=sticky-cookie",
|
||||
"traefik.http.services.my-service.loadBalancer.healthcheck.path=/health",
|
||||
"traefik.http.services.my-service.loadBalancer.healthcheck.interval=10s",
|
||||
"traefik.http.services.my-service.loadBalancer.healthcheck.timeout=3s",
|
||||
"traefik.http.services.my-service.loadBalancer.passHostHeader=true",
|
||||
"traefik.http.services.my-service.loadBalancer.serversTransport=customTransport@file",
|
||||
"traefik.http.services.my-service.loadBalancer.responseForwarding.flushInterval=150ms"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Field | Description | Required |
|
||||
|----------|------------------------------------------|----------|
|
||||
|`servers`| Represents individual backend instances for your service | Yes |
|
||||
|`sticky`| Defines a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response. | No |
|
||||
|`healthcheck`| Configures health check to remove unhealthy servers from the load balancing rotation. | No |
|
||||
|`passHostHeader`| Allows forwarding of the client Host header to server. By default, `passHostHeader` is true. | No |
|
||||
|`serversTransport`| Allows to reference an [HTTP ServersTransport](./serverstransport.md) configuration for the communication between Traefik and your servers. If no `serversTransport` is specified, the `default@internal` will be used. | No |
|
||||
| `responseForwarding` | Configures how Traefik forwards the response from the backend server to the client.| No |
|
||||
| `responseForwarding.FlushInterval` | Specifies the interval in between flushes to the client while copying the response body. It is a duration in milliseconds, defaulting to 100ms. A negative value means to flush immediately after each write to the client. The `FlushInterval` is ignored when ReverseProxy recognizes a response as a streaming response; for such responses, writes are flushed to the client immediately. | No |
|
||||
|
||||
#### Servers
|
||||
|
||||
Servers represent individual backend instances for your service. The [service loadBalancer](#service-load-balancer) `servers` option lets you configure the list of instances that will handle incoming requests.
|
||||
|
||||
##### Configuration Options
|
||||
|
||||
| Field | Description | Required |
|
||||
|----------|------------------------------------------|----------|
|
||||
|`url`| Points to a specific instance. | Yes for File provider, No for [Docker provider](../../other-providers/docker.md) |
|
||||
|`weight`| Allows for weighted load balancing on the servers. | No |
|
||||
|`preservePath`| Allows to preserve the URL path. | No |
|
||||
|
||||
#### Health Check
|
||||
|
||||
The `healthcheck` option configures health check to remove unhealthy servers from the load balancing rotation. Traefik will consider HTTP(s) servers healthy as long as they return a status code to the health check request (carried out every interval) between `2XX` and `3XX`, or matching the configured status. For gRPC servers, Traefik will consider them healthy as long as they return SERVING to [gRPC health check v1 requests](https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
|
||||
|
||||
To propagate status changes (e.g. all servers of this service are down) upwards, HealthCheck must also be enabled on the parent(s) of this service.
|
||||
|
||||
Below are the available options for the health check mechanism:
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|----------|------------------------------------------|----------|--------|
|
||||
|`path`| Defines the server URL path for the health check endpoint. | "" | Yes |
|
||||
|`scheme`| Replaces the server URL scheme for the health check endpoint. | | No |
|
||||
|`mode`| If defined to `grpc`, will use the gRPC health check protocol to probe the server. | http | No |
|
||||
|`hostname`| Defines the value of hostname in the Host header of the health check request. | "" | No |
|
||||
|`port`| Replaces the server URL port for the health check endpoint. | | No |
|
||||
|`interval`| Defines the frequency of the health check calls. | 30s | No |
|
||||
|`timeout`| Defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. | 5s | No |
|
||||
|`headers`| Defines custom headers to be sent to the health check endpoint. | | No |
|
||||
|`followRedirects`| Defines whether redirects should be followed during the health check calls. | true | No |
|
||||
|`hostname`| Defines the value of hostname in the Host header of the health check request. | "" | No |
|
||||
|`method`| Defines the HTTP method that will be used while connecting to the endpoint. | GET | No |
|
||||
|`status`| Defines the expected HTTP status code of the response to the health check request. | | No |
|
||||
|
||||
## Weighted Round Robin (WRR)
|
||||
|
||||
The WRR is able to load balance the requests between multiple services based on weights.
|
||||
|
||||
This strategy is only available to load balance between services and not between servers.
|
||||
|
||||
!!! info "Supported Providers"
|
||||
|
||||
This strategy can be defined currently with the [File](../../../install-configuration/providers/others/file.md) or [IngressRoute](../../../install-configuration/providers/kubernetes/kubernetes-ingress.md) providers. To load balance between servers based on weights, the Load Balancer service should be used instead.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
app:
|
||||
weighted:
|
||||
services:
|
||||
- name: appv1
|
||||
weight: 3
|
||||
- name: appv2
|
||||
weight: 1
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.app]
|
||||
[[http.services.app.weighted.services]]
|
||||
name = "appv1"
|
||||
weight = 3
|
||||
[[http.services.app.weighted.services]]
|
||||
name = "appv2"
|
||||
weight = 1
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
[[http.services.appv1.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
[[http.services.appv2.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
### Health Check
|
||||
|
||||
HealthCheck enables automatic self-healthcheck for this service, i.e. whenever one of its children is reported as down, this service becomes aware of it, and takes it into account (i.e. it ignores the down child) when running the load-balancing algorithm. In addition, if the parent of this service also has HealthCheck enabled, this service reports to its parent any status change.
|
||||
|
||||
!!! note "Behavior"
|
||||
|
||||
If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail.
|
||||
|
||||
HealthCheck on Weighted services can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md).
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
app:
|
||||
weighted:
|
||||
healthCheck: {}
|
||||
services:
|
||||
- name: appv1
|
||||
weight: 3
|
||||
- name: appv2
|
||||
weight: 1
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.app]
|
||||
[http.services.app.weighted.healthCheck]
|
||||
[[http.services.app.weighted.services]]
|
||||
name = "appv1"
|
||||
weight = 3
|
||||
[[http.services.app.weighted.services]]
|
||||
name = "appv2"
|
||||
weight = 1
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
[http.services.appv1.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.appv1.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
[http.services.appv2.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.appv2.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
## Mirroring
|
||||
|
||||
The mirroring is able to mirror requests sent to a service to other services. Please note that by default the whole request is buffered in memory while it is being mirrored. See the `maxBodySize` option in the example below for how to modify this behaviour. You can also omit the request body by setting the `mirrorBody` option to false.
|
||||
|
||||
!!! info "Supported Providers"
|
||||
|
||||
This strategy can be defined currently with the [File](../../../install-configuration/providers/others/file.md) or [IngressRoute](../../../install-configuration/providers/kubernetes/kubernetes-ingress.md) providers.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
mirrored-api:
|
||||
mirroring:
|
||||
service: appv1
|
||||
# mirrorBody defines whether the request body should be mirrored.
|
||||
# Default value is true.
|
||||
mirrorBody: false
|
||||
# maxBodySize is the maximum size allowed for the body of the request.
|
||||
# If the body is larger, the request is not mirrored.
|
||||
# Default value is -1, which means unlimited size.
|
||||
maxBodySize: 1024
|
||||
mirrors:
|
||||
- name: appv2
|
||||
percent: 10
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.mirrored-api]
|
||||
[http.services.mirrored-api.mirroring]
|
||||
service = "appv1"
|
||||
# maxBodySize is the maximum size in bytes allowed for the body of the request.
|
||||
# If the body is larger, the request is not mirrored.
|
||||
# Default value is -1, which means unlimited size.
|
||||
maxBodySize = 1024
|
||||
# mirrorBody defines whether the request body should be mirrored.
|
||||
# Default value is true.
|
||||
mirrorBody = false
|
||||
[[http.services.mirrored-api.mirroring.mirrors]]
|
||||
name = "appv2"
|
||||
percent = 10
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
[[http.services.appv1.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
[[http.services.appv2.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
### Health Check
|
||||
|
||||
HealthCheck enables automatic self-healthcheck for this service, i.e. if the main handler of the service becomes unreachable, the information is propagated upwards to its parent.
|
||||
|
||||
!!! note "Behavior"
|
||||
|
||||
If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail.
|
||||
|
||||
HealthCheck on Mirroring services can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md).
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
mirrored-api:
|
||||
mirroring:
|
||||
healthCheck: {}
|
||||
service: appv1
|
||||
mirrors:
|
||||
- name: appv2
|
||||
percent: 10
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.mirrored-api]
|
||||
[http.services.mirrored-api.mirroring]
|
||||
service = "appv1"
|
||||
[http.services.mirrored-api.mirroring.healthCheck]
|
||||
[[http.services.mirrored-api.mirroring.mirrors]]
|
||||
name = "appv2"
|
||||
percent = 10
|
||||
|
||||
[http.services.appv1]
|
||||
[http.services.appv1.loadBalancer]
|
||||
[http.services.appv1.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.appv1.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.appv2]
|
||||
[http.services.appv2.loadBalancer]
|
||||
[http.services.appv1.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.appv2.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
## Failover
|
||||
|
||||
A failover service job is to forward all requests to a fallback service when the main service becomes unreachable.
|
||||
|
||||
!!! info "Relation to HealthCheck"
|
||||
The failover service relies on the HealthCheck system to get notified when its main service becomes unreachable, which means HealthCheck needs to be enabled and functional on the main service. However, HealthCheck does not need to be enabled on the failover service itself for it to be functional. It is only required in order to propagate upwards the information when the failover itself becomes down (i.e. both its main and its fallback are down too).
|
||||
|
||||
!!! info "Supported Provider"
|
||||
This strategy can currently only be defined with the [File](../../../install-configuration/providers/others/file.md) provider.
|
||||
|
||||
### HealthCheck
|
||||
|
||||
HealthCheck enables automatic self-healthcheck for this service, i.e. if the main and the fallback services become unreachable, the information is propagated upwards to its parent.
|
||||
|
||||
!!! note "Behavior"
|
||||
|
||||
If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail.
|
||||
|
||||
HealthCheck on a Failover service can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md).
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
app:
|
||||
failover:
|
||||
healthCheck: {}
|
||||
service: main
|
||||
fallback: backup
|
||||
|
||||
main:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
|
||||
backup:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /status
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://private-ip-server-2/"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.app]
|
||||
[http.services.app.failover.healthCheck]
|
||||
[http.services.app.failover]
|
||||
service = "main"
|
||||
fallback = "backup"
|
||||
|
||||
[http.services.main]
|
||||
[http.services.main.loadBalancer]
|
||||
[http.services.main.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.main.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
|
||||
[http.services.backup]
|
||||
[http.services.backup.loadBalancer]
|
||||
[http.services.backup.loadBalancer.healthCheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
[[http.services.backup.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
```
|
@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "Traefik AddPrefix Documentation"
|
||||
description: "Learn how to implement the HTTP AddPrefix middleware in Traefik Proxy to updates request paths before being forwarded. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `addPrefix` middleware updates the path of a request before forwarding it.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Prefixing with /foo
|
||||
http:
|
||||
middlewares:
|
||||
add-foo:
|
||||
addPrefix:
|
||||
prefix: "/foo"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Prefixing with /foo
|
||||
[http.middlewares]
|
||||
[http.middlewares.add-foo.addPrefix]
|
||||
prefix = "/foo"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Prefixing with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Prefixing with /foo
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Prefixing with /foo
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: add-foo
|
||||
spec:
|
||||
addPrefix:
|
||||
prefix: /foo
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `prefix` | String to add **before** the current path in the requested URL. It should include a leading slash (`/`). | "" | Yes |
|
@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "Traefik BasicAuth Documentation"
|
||||
description: "The HTTP basic authentication (BasicAuth) middleware in Traefik Proxy restricts access to your Services to known users. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `basicAuth` middleware grants access to services to authorized users only.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Declaring the user list
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Declaring the user list
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.basicAuth]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Declaring the user list
|
||||
#
|
||||
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
|
||||
# To create user:password pair, it's possible to use this command:
|
||||
# echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
|
||||
#
|
||||
# Also, note that dollar signs should NOT be doubled when not evaluated (e.g. Ansible docker_container module).
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Declaring the user list
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
basicAuth:
|
||||
secret: secretName
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `users` | Array of authorized users. Each user must be declared using the `name:hashed-password` format. (More information [here](#users))| "" | No |
|
||||
| `usersFile` | Path to an external file that contains the authorized users for the middleware. <br />The file content is a list of `name:hashed-password`. (More information [here](#usersfile)) | "" | No |
|
||||
| `realm` | Allow customizing the realm for the authentication.| "traefik" | No |
|
||||
| `headerField` | Allow defining a header field to store the authenticated user.| "" | No |
|
||||
| `removeHeader` | Allow removing the authorization header before forwarding the request to your service. | false | No |
|
||||
|
||||
### Passwords format
|
||||
|
||||
Passwords must be hashed using MD5, SHA1, or BCrypt.
|
||||
Use `htpasswd` to generate the passwords.
|
||||
|
||||
### users & usersFile
|
||||
|
||||
- If both `users` and `usersFile` are provided, they are merged. The contents of `usersFile` have precedence over the values in users.
|
||||
- Because referencing a file path isn’t feasible on Kubernetes, the `users` & `usersFile` field isn’t used in Kubernetes IngressRoute. Instead, use the `secret` field.
|
||||
|
||||
#### Kubernetes Secrets
|
||||
|
||||
The option `users` supports Kubernetes secrets.
|
||||
|
||||
!!! note "Kubernetes `kubernetes.io/basic-auth` secret type"
|
||||
|
||||
Kubernetes supports a special `kubernetes.io/basic-auth` secret type.
|
||||
This secret must contain two keys: `username` and `password`.
|
||||
|
||||
Please note that these keys are not hashed or encrypted in any way, and therefore is less secure than other methods.
|
||||
You can find more information on the [Kubernetes Basic Authentication Secret Documentation](https://kubernetes.io/docs/concepts/configuration/secret/#basic-authentication-secret)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,76 @@
|
||||
---
|
||||
title: "Traefik Buffering Documentation"
|
||||
description: "The HTTP buffering middleware in Traefik Proxy limits the size of requests that can be forwarded to Services. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `buffering` middleware limits the size of requests that can be forwarded to services.
|
||||
|
||||
With buffering, Traefik reads the entire request into memory (possibly buffering large requests into disk), and rejects requests that are over a specified size limit.
|
||||
|
||||
This can help services avoid large amounts of data (`multipart/form-data` for example), and can minimize the time spent sending data to a Service
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Sets the maximum request body to 2MB
|
||||
http:
|
||||
middlewares:
|
||||
limit:
|
||||
buffering:
|
||||
maxRequestBodyBytes: 2000000
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Sets the maximum request body to 2MB
|
||||
[http.middlewares]
|
||||
[http.middlewares.limit.buffering]
|
||||
maxRequestBodyBytes = 2000000
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Sets the maximum request body to 2MB
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Sets the maximum request body to 2MB
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Sets the maximum request body to 2MB
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: limit
|
||||
spec:
|
||||
buffering:
|
||||
maxRequestBodyBytes: 2000000
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|:--------|:---------|
|
||||
| `maxRequestBodyBytes` | Maximum allowed body size for the request (in bytes). <br /> If the request exceeds the allowed size, it is not forwarded to the Service, and the client gets a `413` (Request Entity Too Large) response. | 0 | No |
|
||||
| `memRequestBodyBytes` | Threshold (in bytes) from which the request will be buffered on disk instead of in memory with the `memRequestBodyBytes` option.| 1048576 | No |
|
||||
| `maxResponseBodyBytes` | Maximum allowed response size from the Service (in bytes). <br /> If the response exceeds the allowed size, it is not forwarded to the client. The client gets a `500` (Internal Server Error) response instead. | 0 | No |
|
||||
| `memResponseBodyBytes` | Threshold (in bytes) from which the response will be buffered on disk instead of in memory with the `memResponseBodyBytes` option.| 1048576 | No |
|
||||
| `retryExpression` | Replay the request using `retryExpression`.<br /> More information [here](#retryexpression). | "" | No |
|
||||
|
||||
### retryExpression
|
||||
|
||||
The retry expression is defined as a logical combination of the functions below with the operators AND (`&&`) and OR (`||`).
|
||||
At least one function is required:
|
||||
|
||||
- `Attempts()` number of attempts (the first one counts).
|
||||
- `ResponseCode()` response code of the Service.
|
||||
- `IsNetworkError()` whether the response code is related to networking error.
|
@ -0,0 +1,171 @@
|
||||
---
|
||||
title: "Traefik Chain Middleware Documentation"
|
||||
description: "The HTTP chain middleware lets you define reusable combinations of other middleware, to reuse the same groups. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `chain` middleware enables you to define reusable combinations of other pieces of middleware.
|
||||
It makes it effortless to reuse the same groups.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Below is an example of a Chain containing `AllowList`, `BasicAuth`, and `RedirectScheme`.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# ...
|
||||
http:
|
||||
routers:
|
||||
router1:
|
||||
service: service1
|
||||
middlewares:
|
||||
- secured
|
||||
rule: "Host(`mydomain`)"
|
||||
|
||||
middlewares:
|
||||
secured:
|
||||
chain:
|
||||
middlewares:
|
||||
- https-only
|
||||
- known-ips
|
||||
- auth-users
|
||||
|
||||
auth-users:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
|
||||
https-only:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
|
||||
known-ips:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "192.168.1.7"
|
||||
- "127.0.0.1/32"
|
||||
|
||||
services:
|
||||
service1:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://127.0.0.1:80"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# ...
|
||||
[http.routers]
|
||||
[http.routers.router1]
|
||||
service = "service1"
|
||||
middlewares = ["secured"]
|
||||
rule = "Host(`mydomain`)"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.secured.chain]
|
||||
middlewares = ["https-only", "known-ips", "auth-users"]
|
||||
|
||||
[http.middlewares.auth-users.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
||||
|
||||
[http.middlewares.https-only.redirectScheme]
|
||||
scheme = "https"
|
||||
|
||||
[http.middlewares.known-ips.ipAllowList]
|
||||
sourceRange = ["192.168.1.7", "127.0.0.1/32"]
|
||||
|
||||
[http.services]
|
||||
[http.services.service1]
|
||||
[http.services.service1.loadBalancer]
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:80"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.routers.router1.service=service1"
|
||||
- "traefik.http.routers.router1.middlewares=secured"
|
||||
- "traefik.http.routers.router1.rule=Host(`mydomain`)"
|
||||
- "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users"
|
||||
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.routers.router1.service=service1",
|
||||
"traefik.http.routers.router1.middlewares=secured",
|
||||
"traefik.http.routers.router1.rule=Host(`mydomain`)",
|
||||
"traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users",
|
||||
"traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"traefik.http.middlewares.https-only.redirectscheme.scheme=https",
|
||||
"traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32",
|
||||
"traefik.http.services.service1.loadbalancer.server.port=80"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`mydomain`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: secured
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: secured
|
||||
spec:
|
||||
chain:
|
||||
middlewares:
|
||||
- name: https-only
|
||||
- name: known-ips
|
||||
- name: auth-users
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: auth-users
|
||||
spec:
|
||||
basicAuth:
|
||||
users:
|
||||
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: https-only
|
||||
spec:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: known-ips
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 192.168.1.7
|
||||
- 127.0.0.1/32
|
||||
```
|
||||
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|:--------|:---------|
|
||||
| `middlewares` | List of middlewares to chain.<br /> The middlewares have to be in the same namespace as the `chain` middleware. | [] | Yes |
|
@ -0,0 +1,143 @@
|
||||
---
|
||||
title: "Traefik CircuitBreaker Documentation"
|
||||
description: "The HTTP circuit breaker in Traefik Proxy prevents stacking requests to unhealthy Services, resulting in cascading failures. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The HTTP circuit breaker prevents stacking requests to unhealthy Services, resulting in cascading failures.
|
||||
|
||||
When your system is healthy, the circuit is closed (normal operations).
|
||||
When your system becomes unhealthy, the circuit opens, and the requests are no longer forwarded, but instead are handled by a fallback mechanism.
|
||||
|
||||
To assess if your system is healthy, the circuit breaker constantly monitors the services.
|
||||
|
||||
The circuit breaker only analyzes what happens *after* its position within the middleware chain. What happens *before* has no impact on its state.
|
||||
|
||||
Each router gets its own instance of a given circuit breaker.
|
||||
One circuit breaker instance can be open while the other remains closed: their state is not shared.
|
||||
|
||||
This is the expected behavior, we want you to be able to define what makes a service healthy without having to declare a circuit breaker for each route.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Latency Check
|
||||
http:
|
||||
middlewares:
|
||||
latency-check:
|
||||
circuitBreaker:
|
||||
expression: "LatencyAtQuantileMS(50.0) > 100"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Latency Check
|
||||
[http.middlewares]
|
||||
[http.middlewares.latency-check.circuitBreaker]
|
||||
expression = "LatencyAtQuantileMS(50.0) > 100"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Latency Check
|
||||
labels:
|
||||
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//..
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Latency Check
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: latency-check
|
||||
spec:
|
||||
circuitBreaker:
|
||||
expression: LatencyAtQuantileMS(50.0) > 100
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|:--------|:---------|
|
||||
| `expression` | Condition to open the circuit breaker and applies the fallback mechanism instead of calling your services.<br />More information [here](#expression) | 100ms | No |
|
||||
| `checkPeriod` | The interval between successive checks of the circuit breaker condition (when in standby state). | 100ms | No |
|
||||
| `fallbackDuration` | The duration for which the circuit breaker will wait before trying to recover (from a tripped state). | 10s | No |
|
||||
| `recoveryDuration` | The duration for which the circuit breaker will try to recover (as soon as it is in recovering state). | 10s | No |
|
||||
| `responseCode` | The status code that the circuit breaker will return while it is in the open state. | 503 | No |
|
||||
|
||||
### expression
|
||||
|
||||
The `expression` option can check three different metrics:
|
||||
|
||||
| Metrics | Description | Example |
|
||||
|:------|:------------|:--------|
|
||||
| `NetworkErrorRatio` | The network error ratio to open the circuit breaker. | `NetworkErrorRatio() > 0.30` opens the circuit breaker at a 30% ratio of network errors |
|
||||
| `ResponseCodeRatio` | The status code ratio to open the circuit breaker.<br />More information [below](#responsecoderatio) | `ResponseCodeRatio(500, 600, 0, 600) > 0.25` opens the circuit breaker if 25% of the requests returned a 5XX status (amongst the request that returned a status code from 0 to 5XX) |
|
||||
| `LatencyAtQuantileMS` | The latency at a quantile in milliseconds to open the circuit breaker when a given proportion of your requests become too slow.<br /> Only floating point number (with the trailing .0) for the quantile value. | `LatencyAtQuantileMS(50.0) > 100` opens the circuit breaker when the median latency (quantile 50) reaches 100ms. |
|
||||
|
||||
#### ResponseCodeRatio
|
||||
|
||||
- It accepts four parameters, `from`, `to`, `dividedByFrom`, `dividedByTo`.
|
||||
- The operation that will be computed is sum(`to` -> `from`) / sum (`dividedByFrom` -> `dividedByTo`). If sum (`dividedByFrom` -> `dividedByTo`) equals 0, then `ResponseCodeRatio` returns 0.
|
||||
- `from` is inclusive, `to` is exclusive.
|
||||
|
||||
#### Using Multiple Metrics
|
||||
|
||||
You can combine multiple metrics using operators in your `expression`.
|
||||
|
||||
Supported operators are:
|
||||
|
||||
- AND (`&&`)
|
||||
- OR (`||`)
|
||||
|
||||
For example, `ResponseCodeRatio(500, 600, 0, 600) > 0.30 || NetworkErrorRatio() > 0.10` triggers the circuit breaker when 30% of the requests return a 5XX status code, or when the ratio of network errors reaches 10%.
|
||||
|
||||
#### Operators
|
||||
|
||||
Here is the list of supported operators:
|
||||
|
||||
- Greater than (`>`)
|
||||
- Greater or equal than (`>=`)
|
||||
- Lesser than (`<`)
|
||||
- Lesser or equal than (`<=`)
|
||||
- Equal (`==`)
|
||||
- Not Equal (`!=`)
|
||||
|
||||
### Fallback mechanism
|
||||
|
||||
The fallback mechanism returns a `HTTP 503 Service Unavailable` to the client instead of calling the target service.
|
||||
This behavior cannot be configured.
|
||||
|
||||
## State
|
||||
|
||||
There are three possible states for your circuit breaker:
|
||||
|
||||
- `Closed` (your service operates normally).
|
||||
- `Open` (the fallback mechanism takes over your service).
|
||||
- `Recovering` (the circuit breaker tries to resume normal operations by progressively sending requests to your service).
|
||||
|
||||
### Closed
|
||||
|
||||
While the circuit is closed, the circuit breaker only collects metrics to analyze the behavior of the requests.
|
||||
|
||||
At specified intervals (`checkPeriod`), the circuit breaker evaluates `expression` to decide if its state must change.
|
||||
|
||||
### Open
|
||||
|
||||
While open, the fallback mechanism takes over the normal service calls for a duration of `FallbackDuration`.
|
||||
The fallback mechanism returns a `HTTP 503` (or `ResponseCode`) to the client.
|
||||
After this duration, it enters the recovering state.
|
||||
|
||||
### Recovering
|
||||
|
||||
While recovering, the circuit breaker sends linearly increasing amounts of requests to your service (for `RecoveryDuration`).
|
||||
If your service fails during recovery, the circuit breaker opens again.
|
||||
If the service operates normally during the entire recovery duration, then the circuit breaker closes.
|
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: "Traefik Compress Documentation"
|
||||
description: "Traefik Proxy's HTTP middleware lets you compress responses before sending them to the client. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `compress` middleware compresses response. It supports Gzip, Brotli and Zstandard compression
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Enable compression
|
||||
http:
|
||||
middlewares:
|
||||
test-compress:
|
||||
compress: {}
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Enable compression
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-compress.compress]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Enable compression
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Enable compression
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-compress.compress=true"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Enable compression
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-compress
|
||||
spec:
|
||||
compress: {}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
|`excludedContentTypes` | List of content types to compare the `Content-Type` header of the incoming requests and responses before compressing. <br /> The responses with content types defined in `excludedContentTypes` are not compressed. <br /> Content types are compared in a case-insensitive, whitespace-ignored manner. <br /> **The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.** | "" | No |
|
||||
|`defaultEncoding` | specifies the default encoding if the `Accept-Encoding` header is not in the request or contains a wildcard (`*`). | "" | No |
|
||||
|`encodings` | Specifies the list of supported compression encodings. At least one encoding value must be specified, and valid entries are `zstd` (Zstandard), `br` (Brotli), and `gzip` (Gzip). The order of the list also sets the priority, the top entry has the highest priority. | zstd, br, gzip | No |
|
||||
| `includedContentTypes` | List of content types to compare the `Content-Type` header of the responses before compressing. <br /> The responses with content types defined in `includedContentTypes` are compressed. <br /> Content types are compared in a case-insensitive, whitespace-ignored manner.<br /> **The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.** | "" | No |
|
||||
| `minResponseBodyBytes` | `Minimum amount of bytes a response body must have to be compressed. <br />Responses smaller than the specified values will **not** be compressed. | 1024 | No |
|
||||
|
||||
## Compression activation
|
||||
|
||||
The activation of compression, and the compression method choice rely (among other things) on the request's `Accept-Encoding` header.
|
||||
|
||||
Responses are compressed when the following criteria are all met:
|
||||
|
||||
- The `Accept-Encoding` request header contains `gzip`, `*`, and/or `br`, and/or `zstd` with or without [quality values](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values).
|
||||
If the `Accept-Encoding` request header is absent, the response won't be encoded.
|
||||
If it is present, but its value is the empty string, then compression is turned off.
|
||||
- The response is not already compressed, that is the `Content-Encoding` response header is not already set.
|
||||
- The response`Content-Type` header is not one among the `excludedContentTypes` options, or is one among the `includedContentTypes` options.
|
||||
- The response body is larger than the configured minimum amount of bytes(option `minResponseBodyBytes`) (default is `1024`).
|
||||
|
||||
## Empty Content-Type Header
|
||||
|
||||
If the `Content-Type` header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
||||
It will also set the `Content-Type` header according to the detected MIME type.
|
||||
|
||||
## GRPC application
|
||||
|
||||
Note that `application/grpc` is never compressed.
|
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Traefik ContentType Documentation"
|
||||
description: "Traefik Proxy's HTTP middleware automatically sets the `Content-Type` header value when it is not set by the backend. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `contentType` middleware sets the `Content-Type` header value to the media type detected from the response content,
|
||||
when it is not set by the backend.
|
||||
|
||||
!!! info
|
||||
|
||||
The `contentType` middleware only applies when Traefik detects the MIME type. If any middleware (such as Headers or Compress) sets the `contentType` header at any point in the chain, the `contentType` middleware has no effect.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Enable auto-detection
|
||||
http:
|
||||
middlewares:
|
||||
autodetect:
|
||||
contentType: {}
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Enable auto-detection
|
||||
[http.middlewares]
|
||||
[http.middlewares.autodetect.contentType]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Enable auto-detection
|
||||
labels:
|
||||
- "traefik.http.middlewares.autodetect.contenttype=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Enable auto-detection
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.autodetect.contenttype=true"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Enable auto-detection
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: autodetect
|
||||
spec:
|
||||
contentType: {}
|
||||
```
|
@ -0,0 +1,87 @@
|
||||
---
|
||||
title: "Traefik DigestAuth Documentation"
|
||||
description: "Traefik Proxy's HTTP DigestAuth middleware restricts access to your services to known users. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `DigestAuth` middleware grants access to services to authorized users only.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Declaring the user list
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
digestAuth:
|
||||
users:
|
||||
- "test:traefik:a2688e031edb4be6a3797f3882655c05"
|
||||
- "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Declaring the user list
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.digestAuth]
|
||||
users = [
|
||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Declaring the user list
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Declaring the user list
|
||||
{
|
||||
//...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Declaring the user list
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
digestAuth:
|
||||
secret: userssecret
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:---------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `users` | Array of authorized users. Each user must be declared using the `name:realm:encoded-password` format.<br /> The option `users` supports Kubernetes secrets.<br />(More information [here](#users--usersfile))| [] | No |
|
||||
| `usersFile` | Path to an external file that contains the authorized users for the middleware. <br />The file content is a list of `name:realm:encoded-password`. (More information [here](#users--usersfile)) | "" | No |
|
||||
| `realm` | Allow customizing the realm for the authentication.| "traefik" | No |
|
||||
| `headerField` | Allow defining a header field to store the authenticated user.| "" | No |
|
||||
| `removeHeader` | Allow removing the authorization header before forwarding the request to your service. | false | No |
|
||||
|
||||
### Passwords format
|
||||
|
||||
Passwords must be hashed using MD5, SHA1, or BCrypt.
|
||||
Use `htpasswd` to generate the passwords.
|
||||
|
||||
### users & usersFile
|
||||
|
||||
- If both `users` and `usersFile` are provided, they are merged. The contents of `usersFile` have precedence over the values in users.
|
||||
- Because referencing a file path isn’t feasible on Kubernetes, the `users` & `usersFile` field isn’t used in Kubernetes IngressRoute. Instead, use the `secret` field.
|
||||
|
||||
### Kubernetes Secrets
|
||||
|
||||
On Kubernetes, you don’t use the `users` or `usersFile` fields. Instead, you reference a Kubernetes secret using the `secret` field in your Middleware resource. This secret can be one of two types:
|
||||
|
||||
- `kubernetes.io/basic-auth secret`: This secret type contains two keys—`username` and `password`—but is generally suited for a smaller number of users. Please note that these keys are not hashed or encrypted in any way, and therefore is less secure than the other method.
|
||||
- Opaque secret with a users field: Here, the secret contains a single string field (often called `users`) where each line represents a user. This approach allows you to store multiple users in one secret.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "Traefik Errors Documentation"
|
||||
description: "In Traefik Proxy, the Errors middleware returns custom pages according to configured ranges of HTTP Status codes. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `errors` middleware returns a custom page in lieu of the default, according to configured ranges of HTTP Status codes.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
http:
|
||||
middlewares:
|
||||
test-errors:
|
||||
errors:
|
||||
status:
|
||||
- "500"
|
||||
- "501"
|
||||
- "503"
|
||||
- "505-599"
|
||||
service: error-handler-service
|
||||
query: "/{status}.html"
|
||||
|
||||
services:
|
||||
# ... definition of the error-handler-service
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-errors.errors]
|
||||
status = ["500","501","503","505-599"]
|
||||
service = "error-handler-service"
|
||||
query = "/{status}.html"
|
||||
|
||||
[http.services]
|
||||
# ... definition of the error-handler-service
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Dynamic Custom Error Page for 5XX Status Code
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599"
|
||||
- "traefik.http.middlewares.test-errors.errors.service=error-handler-service"
|
||||
- "traefik.http.middlewares.test-errors.errors.query=/{status}.html"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599",
|
||||
"traefik.http.middlewares.test-errors.errors.service=error-handler-service",
|
||||
"traefik.http.middlewares.test-errors.errors.query=/{status}.html"
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-errors
|
||||
spec:
|
||||
errors:
|
||||
status:
|
||||
- "500"
|
||||
- "501"
|
||||
- "503"
|
||||
- "505-599"
|
||||
query: /{status}.html
|
||||
service:
|
||||
name: error-handler-service
|
||||
port: 80
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `status` | Defines which status or range of statuses should result in an error page.<br/> The status code ranges are inclusive (`505-599` will trigger with every code between `505` and `599`, `505` and `599` included).<br /> You can define either a status code as a number (`500`), as multiple comma-separated numbers (`500,502`), as ranges by separating two codes with a dash (`505-599`), or a combination of the two (`404,418,505-599`). | [] | No |
|
||||
| `service` | The service that will serve the new requested error page.<br /> More information [here](#service-and-hostheader). | "" | No |
|
||||
| `query` | The URL for the error page (hosted by `service`).<br /> More information [here](#query) | "" | No |
|
||||
|
||||
### service and HostHeader
|
||||
|
||||
By default, the client `Host` header value is forwarded to the configured error service.
|
||||
To forward the `Host` value corresponding to the configured error service URL,
|
||||
the [`passHostHeader`](../../../../routing/services/index.md#pass-host-header) option must be set to `false`.
|
||||
|
||||
!!!info "Kubernetes"
|
||||
When specifying a service in Kubernetes (e.g., in an IngressRoute), you need to reference the `name`, `namespace`, and `port` of your Kubernetes Service resource. For example, `my-service.my-namespace@kubernetescrd` (or `my-service.my-namespace@kubernetescrd:80`) ensures that requests go to the correct service and port.
|
||||
|
||||
### query
|
||||
|
||||
There are multiple variables that can be placed in the `query` option to insert values in the URL.
|
||||
|
||||
The table below lists all the available variables and their associated values.
|
||||
|
||||
| Variable | Value |
|
||||
|------------|------------------------------------------------------------------|
|
||||
| `{status}` | The response status code. |
|
||||
| `{url}` | The [escaped](https://pkg.go.dev/net/url#QueryEscape) request URL.|
|
@ -0,0 +1,98 @@
|
||||
---
|
||||
title: "Traefik ForwardAuth Documentation"
|
||||
description: "In Traefik Proxy, the HTTP ForwardAuth middleware delegates authentication to an external Service. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The `forwardAuth` middleware delegates authentication to an external service.
|
||||
If the service answers with a 2XX code, access is granted, and the original request is performed.
|
||||
Otherwise, the response from the authentication server is returned.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Forward authentication to example.com
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://example.com/auth"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Forward authentication to example.com
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://example.com/auth"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Forward authentication to example.com
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Forward authentication to example.com
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Forward authentication to example.com
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://example.com/auth
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `address` | Authentication server address. | "" | Yes |
|
||||
| `trustForwardHeader` | Trust all `X-Forwarded-*` headers. | false | No |
|
||||
| `authResponseHeaders` | List of headers to copy from the authentication server response and set on forwarded request, replacing any existing conflicting headers. | [] | No |
|
||||
| `authResponseHeadersRegex` | Regex to match by the headers to copy from the authentication server response and set on forwarded request, after stripping all headers that match the regex.<br /> More information [here](#authresponseheadersregex). | "" | No |
|
||||
| `authRequestHeaders` | List of the headers to copy from the request to the authentication server. <br /> It allows filtering headers that should not be passed to the authentication server. <br /> If not set or empty, then all request headers are passed. | [] | No |
|
||||
| `addAuthCookiesToResponse` | List of cookies to copy from the authentication server to the response, replacing any existing conflicting cookie from the forwarded response.<br /> Please note that all backend cookies matching the configured list will not be added to the response. | [] | No |
|
||||
| `forwardBody` | Sets the `forwardBody` option to `true` to send the Body. As body is read inside Traefik before forwarding, this breaks streaming. | false | No |
|
||||
| `maxBodySize` | Set the `maxBodySize` to limit the body size in bytes. If body is bigger than this, it returns a 401 (unauthorized). | -1 | No |
|
||||
| `headerField` | Defines a header field to store the authenticated user. | "" | No |
|
||||
| `preserveLocationHeader` | Defines whether to forward the Location header to the client as is or prefix it with the domain name of the authentication server. | false | No |
|
||||
| `PreserveRequestMethod` | Defines whether to preserve the original request method while forwarding the request to the authentication server. | false | No |
|
||||
| `tls.ca` | Sets the path to the certificate authority used for the secured connection to the authentication server, it defaults to the system bundle. | "" | No |
|
||||
| `tls.cert` | Sets the path to the public certificate used for the secure connection to the authentication server. When using this option, setting the key option is required. | "" | No |
|
||||
| `tls.key` | Sets the path to the private key used for the secure connection to the authentication server. When using this option, setting the `cert` option is required. | "" | No |
|
||||
| `tls.caSecret` | Defines the secret that contains the certificate authority used for the secured connection to the authentication server, it defaults to the system bundle. **This option is only available for the Kubernetes CRD**. | | No |
|
||||
| `tls.certSecret` | Defines the secret that contains both the private and public certificates used for the secure connection to the authentication server. **This option is only available for the Kubernetes CRD**. | | No |
|
||||
| `tls.insecureSkipVerify` | During TLS connections, if this option is set to `true`, the authentication server will accept any certificate presented by the server regardless of the host names it covers. | false | No |
|
||||
|
||||
### authResponseHeadersRegex
|
||||
|
||||
It allows partial matching of the regular expression against the header key.
|
||||
|
||||
The start of string (`^`) and end of string (`$`) anchors should be used to ensure a full match against the header key.
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
## Forward-Request Headers
|
||||
|
||||
The following request properties are provided to the forward-auth target endpoint as `X-Forwarded-` headers.
|
||||
|
||||
| Property | Forward-Request Header |
|
||||
|-------------------|------------------------|
|
||||
| HTTP Method | X-Forwarded-Method |
|
||||
| Protocol | X-Forwarded-Proto |
|
||||
| Host | X-Forwarded-Host |
|
||||
| Request URI | X-Forwarded-Uri |
|
||||
| Source IP-Address | X-Forwarded-For |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Traefik GrpcWeb Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, GrpcWeb converts a gRPC Web requests to HTTP/2 gRPC requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `grpcWeb` middleware converts gRPC Web requests to HTTP/2 gRPC requests before forwarding them to the backends.
|
||||
|
||||
!!! tip
|
||||
|
||||
Please note, that Traefik needs to communicate using gRPC with the backends (h2c or HTTP/2 over TLS).
|
||||
Check out the [gRPC](../../../../user-guides/grpc.md) user guide for more details.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-grpcweb:
|
||||
grpcWeb:
|
||||
allowOrigins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-grpcweb.grpcWeb]
|
||||
allowOrigins = ["*"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-grpcweb.grpcweb.allowOrigins=*"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-grpcweb.grpcWeb.allowOrigins=*"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-grpcweb
|
||||
spec:
|
||||
grpcWeb:
|
||||
allowOrigins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:------------------------------------------|:--------|:---------|
|
||||
| `allowOrigins` | List of allowed origins. <br /> A wildcard origin `*` can also be configured to match all requests.<br /> More information [here](#alloworigins). | [] | No |
|
||||
|
||||
### allowOrigins
|
||||
|
||||
More information including how to use the settings can be found at:
|
||||
|
||||
- [Mozilla.org](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)
|
||||
- [w3](https://fetch.spec.whatwg.org/#http-access-control-allow-origin)
|
||||
- [IETF](https://tools.ietf.org/html/rfc6454#section-7.1)
|
@ -0,0 +1,328 @@
|
||||
---
|
||||
title: "Traefik Headers Documentation"
|
||||
description: "In Traefik Proxy, the HTTP headers middleware manages the headers of requests and responses. Read the technical documentation."
|
||||
---
|
||||
|
||||

|
||||
|
||||
The Headers middleware manages the headers of requests and responses.
|
||||
|
||||
By default, the following headers are automatically added when proxying requests:
|
||||
|
||||
| Property | HTTP Header |
|
||||
|---------------------------|----------------------------|
|
||||
| Client's IP | X-Forwarded-For, X-Real-Ip |
|
||||
| Host | X-Forwarded-Host |
|
||||
| Port | X-Forwarded-Port |
|
||||
| Protocol | X-Forwarded-Proto |
|
||||
| Proxy Server's Hostname | X-Forwarded-Server |
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Adding Headers to the Request and the Response
|
||||
|
||||
The following example adds the `X-Script-Name` header to the proxied request and the `X-Custom-Response-Header` header to the response
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
customRequestHeaders:
|
||||
X-Script-Name: "test"
|
||||
customResponseHeaders:
|
||||
X-Custom-Response-Header: "value"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
[http.middlewares.testHeader.headers.customRequestHeaders]
|
||||
X-Script-Name = "test"
|
||||
[http.middlewares.testHeader.headers.customResponseHeaders]
|
||||
X-Custom-Response-Header = "value"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testHeader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testHeader.headers.customresponseheaders.X-Custom-Response-Header=value"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test",
|
||||
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-header
|
||||
spec:
|
||||
headers:
|
||||
customRequestHeaders:
|
||||
X-Script-Name: "test"
|
||||
customResponseHeaders:
|
||||
X-Custom-Response-Header: "value"
|
||||
```
|
||||
|
||||
### Adding and Removing Headers
|
||||
|
||||
In the following example, requests are proxied with an extra `X-Script-Name` header while their `X-Custom-Request-Header` header gets stripped,
|
||||
and responses are stripped of their `X-Custom-Response-Header` header.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
customRequestHeaders:
|
||||
X-Script-Name: "test" # Adds
|
||||
X-Custom-Request-Header: "" # Removes
|
||||
customResponseHeaders:
|
||||
X-Custom-Response-Header: "" # Removes
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
[http.middlewares.testHeader.headers.customRequestHeaders]
|
||||
X-Script-Name = "test" # Adds
|
||||
X-Custom-Request-Header = "" # Removes
|
||||
[http.middlewares.testHeader.headers.customResponseHeaders]
|
||||
X-Custom-Response-Header = "" # Removes
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header="
|
||||
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test",
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header=",
|
||||
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-header
|
||||
spec:
|
||||
headers:
|
||||
customRequestHeaders:
|
||||
X-Script-Name: "test" # Adds
|
||||
X-Custom-Request-Header: "" # Removes
|
||||
customResponseHeaders:
|
||||
X-Custom-Response-Header: "" # Removes
|
||||
```
|
||||
|
||||
### Using Security Headers
|
||||
|
||||
Security-related headers (HSTS headers, Browser XSS filter, etc) can be managed similarly to custom headers as shown above.
|
||||
This functionality makes it possible to easily use security features by adding headers.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
frameDeny: true
|
||||
browserXssFilter: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
frameDeny = true
|
||||
browserXssFilter = true
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testHeader.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.testHeader.headers.browserxssfilter=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.testheader.headers.framedeny=true",
|
||||
"traefik.http.middlewares.testheader.headers.browserxssfilter=true"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-header
|
||||
spec:
|
||||
headers:
|
||||
frameDeny: true
|
||||
browserXssFilter: true
|
||||
```
|
||||
|
||||
### CORS Headers
|
||||
|
||||
CORS (Cross-Origin Resource Sharing) headers can be added and configured in a manner similar to the custom headers above.
|
||||
This functionality allows for more advanced security features to quickly be set.
|
||||
If CORS headers are set, then the middleware does not pass preflight requests to any service,
|
||||
instead the response will be generated and sent back to the client directly.
|
||||
Please note that the example below is by no means authoritative or exhaustive,
|
||||
and should not be used as is for production.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
testHeader:
|
||||
headers:
|
||||
accessControlAllowMethods:
|
||||
- GET
|
||||
- OPTIONS
|
||||
- PUT
|
||||
accessControlAllowHeaders: "*"
|
||||
accessControlAllowOriginList:
|
||||
- https://foo.bar.org
|
||||
- https://example.org
|
||||
accessControlMaxAge: 100
|
||||
addVaryHeader: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
accessControlAllowMethods = ["GET", "OPTIONS", "PUT"]
|
||||
accessControlAllowHeaders = [ "*" ]
|
||||
accessControlAllowOriginList = ["https://foo.bar.org","https://example.org"]
|
||||
accessControlMaxAge = 100
|
||||
addVaryHeader = true
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
|
||||
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100",
|
||||
"traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-header
|
||||
spec:
|
||||
headers:
|
||||
accessControlAllowMethods:
|
||||
- "GET"
|
||||
- "OPTIONS"
|
||||
- "PUT"
|
||||
accessControlAllowHeaders:
|
||||
- "*"
|
||||
accessControlAllowOriginList:
|
||||
- "https://foo.bar.org"
|
||||
- "https://example.org"
|
||||
accessControlMaxAge: 100
|
||||
addVaryHeader: true
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
!!! warning
|
||||
|
||||
Custom headers will overwrite existing headers if they have identical names.
|
||||
|
||||
!!! note ""
|
||||
|
||||
The detailed documentation for security headers can be found in [unrolled/secure](https://github.com/unrolled/secure#available-options).
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
| ----------------------------- | ------------------------------------------------- | --------- | -------- |
|
||||
| `customRequestHeaders` | Lists the header names and values for requests. | [] | No |
|
||||
| `customResponseHeaders` | Lists the header names and values for responses. | [] | No |
|
||||
| `accessControlAllowCredentials` | Indicates if the request can include user credentials.| false | No |
|
||||
| `accessControlAllowHeaders` | Specifies allowed request header names. | [] | No |
|
||||
| `accessControlAllowMethods` | Specifies allowed request methods. | [] | No |
|
||||
| `accessControlAllowOriginList` | Specifies allowed origins. More information [here](#accesscontrolalloworiginlist) | [] | No |
|
||||
| `accessControlAllowOriginListRegex` | Allows origins matching regex. More information [here](#accesscontrolalloworiginlistregex) | [] | No |
|
||||
| `accessControlExposeHeaders` | Specifies which headers are safe to expose to the API of a CORS API specification. | [] | No |
|
||||
| `accessControlMaxAge` | Time (in seconds) to cache preflight requests. | 0 | No |
|
||||
| `addVaryHeader` | Used in conjunction with `accessControlAllowOriginList` to determine whether the `Vary` header should be added or modified to demonstrate that server responses can differ based on the value of the origin header. | false | No |
|
||||
| `allowedHosts` | Lists allowed domain names. | [] | No |
|
||||
| `hostsProxyHeaders` | Specifies header keys for proxied hostname. | [] | No |
|
||||
| `sslProxyHeaders` | Defines a set of header keys with associated values that would indicate a valid HTTPS request. It can be useful when using other proxies (example: `"X-Forwarded-Proto": "https"`). | {} | No |
|
||||
| `stsSeconds` | Max age for `Strict-Transport-Security` header. | 0 | No |
|
||||
| `stsIncludeSubdomains` | If set to `true`, the `includeSubDomains` directive is appended to the `Strict-Transport-Security` header. | false | No |
|
||||
| `stsPreload` | Adds preload flag to STS header. | false | No |
|
||||
| `forceSTSHeader` | Adds STS header for HTTP connections. | false | No |
|
||||
| `frameDeny` | Set `frameDeny` to `true` to add the `X-Frame-Options` header with the value of `DENY`. | false | No |
|
||||
| `customFrameOptionsValue` | allows the `X-Frame-Options` header value to be set with a custom value. This overrides the `FrameDeny` option. | "" | No |
|
||||
| `contentTypeNosniff` | Set `contentTypeNosniff` to true to add the `X-Content-Type-Options` header with the value `nosniff`. | false | No |
|
||||
| `browserXssFilter` | Set `browserXssFilter` to true to add the `X-XSS-Protection` header with the value `1; mode=block`. | false | No |
|
||||
| `customBrowserXSSValue` | allows the `X-XSS-Protection` header value to be set with a custom value. This overrides the `BrowserXssFilter` option. | false | No |
|
||||
| `contentSecurityPolicy` | allows the `Content-Security-Policy` header value to be set with a custom value. | false | No |
|
||||
| `contentSecurityPolicyReportOnly` | allows the `Content-Security-Policy-Report-Only` header value to be set with a custom value. | "" | No |
|
||||
| `publicKey` | Implements HPKP for certificate pinning. | "" | No |
|
||||
| `referrerPolicy` | Controls forwarding of `Referer` header. | "" | No |
|
||||
| `permissionsPolicy` | allows sites to control browser features. | "" | No |
|
||||
| `isDevelopment` | Set `true` when developing to mitigate the unwanted effects of the `AllowedHosts`, SSL, and STS options. Usually testing takes place using HTTP, not HTTPS, and on `localhost`, not your production domain. | false | No |
|
||||
|
||||
### `accessControlAllowOriginList`
|
||||
|
||||
The `accessControlAllowOriginList` indicates whether a resource can be shared by returning different values.
|
||||
|
||||
A wildcard origin `*` can also be configured, and matches all requests.
|
||||
If this value is set by a backend service, it will be overwritten by Traefik.
|
||||
|
||||
This value can contain a list of allowed origins.
|
||||
|
||||
More information including how to use the settings can be found at:
|
||||
|
||||
- [Mozilla.org](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)
|
||||
- [w3](https://fetch.spec.whatwg.org/#http-access-control-allow-origin)
|
||||
- [IETF](https://tools.ietf.org/html/rfc6454#section-7.1)
|
||||
|
||||
Traefik no longer supports the `null` value, as it is [no longer recommended as a return value](https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null).
|
||||
|
||||
### `accessControlAllowOriginListRegex`
|
||||
|
||||
The `accessControlAllowOriginListRegex` option is the counterpart of the `accessControlAllowOriginList` option with regular expressions instead of origin values.
|
||||
It allows all origins that contain any match of a regular expression in the `accessControlAllowOriginList`.
|
||||
|
||||
!!! tip
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "Traefik InFlightReq Documentation"
|
||||
description: "Traefik Proxy's HTTP middleware lets you limit the number of simultaneous in-flight requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `inFlightReq` middleware proactively prevents services from being overwhelmed with high load.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
http:
|
||||
middlewares:
|
||||
test-inflightreq:
|
||||
inFlightReq:
|
||||
amount: 10
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-inflightreq.inFlightReq]
|
||||
amount = 10
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
|
||||
```json tab="Consul Catalog"
|
||||
// Limiting to 10 simultaneous connections
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-inflightreq
|
||||
spec:
|
||||
inFlightReq:
|
||||
amount: 10
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `amount` | The `amount` option defines the maximum amount of allowed simultaneous in-flight request. <br /> The middleware responds with `HTTP 429 Too Many Requests` if there are already `amount` requests in progress (based on the same `sourceCriterion` strategy). | 0 | No |
|
||||
| `sourceCriterion.requestHost` | Whether to consider the request host as the source.<br /> More information about `sourceCriterion`[here](#sourcecriterion). | false | No |
|
||||
| `sourceCriterion.requestHeaderName` | Name of the header used to group incoming requests.<br /> More information about `sourceCriterion`[here](#sourcecriterion). | "" | No |
|
||||
| `sourceCriterion.ipStrategy.depth` | Depth position of the IP to select in the `X-Forwarded-For` header (starting from the right).<br />0 means no depth.<br />If greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty<br />If higher than 0, the `excludedIPs` options is not evaluated.<br /> More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy](#ipstrategy), and [`depth`](#example-of-depth--x-forwarded-for) below. | 0 | No |
|
||||
| `sourceCriterion.ipStrategy.excludedIPs` | Allows Traefik to scan the `X-Forwarded-For` header and select the first IP not in the list.<br />If `depth` is specified, `excludedIPs` is ignored.<br /> More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy](#ipstrategy), and [`excludedIPs`](#example-of-excludedips--x-forwarded-for) below. | | No |
|
||||
| `sourceCriterion.ipStrategy.ipv6Subnet` | If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. <br /> More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy.ipv6Subnet`](#ipstrategyipv6subnet), and [`excludedIPs`](#example-of-excludedips--x-forwarded-for) below. | | No |
|
||||
|
||||
### sourceCriterion
|
||||
|
||||
The `sourceCriterion` option defines what criterion is used to group requests as originating from a common source.
|
||||
If several strategies are defined at the same time, an error will be raised.
|
||||
If none are set, the default is to use the `requestHost`.
|
||||
|
||||
### ipStrategy
|
||||
|
||||
The `ipStrategy` option defines three parameters that configures how Traefik determines the client IP: `depth`, `excludedIPs` and `ipv6Subnet`.
|
||||
|
||||
As a middleware, `inFlightReq` happens before the actual proxying to the backend takes place.
|
||||
In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, that is after it has already passed through the middleware.
|
||||
Therefore, during InFlightReq, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be used and/or relied upon.
|
||||
|
||||
### `ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside 0-128 interval
|
||||
|
||||
#### Example of ipv6Subnet
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| IP | ipv6Subnet | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
### Example of Depth & X-Forwarded-For
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||
|
||||
| X-Forwarded-For | depth | clientIP |
|
||||
|-----------------------------------------|---------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `1` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
|
||||
|
||||
### Example of ExcludedIPs & X-Forwarded-For
|
||||
|
||||
| X-Forwarded-For | excludedIPs | clientIP |
|
||||
|-----------------------------------------|-----------------------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"12.0.0.1,13.0.0.1"` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"10.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
|
@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "Traefik HTTP Middlewares IPAllowList"
|
||||
description: "Learn how to use IPAllowList in HTTP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
`ipAllowList` accepts / refuses requests based on the client IP.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Accepts request from defined IP
|
||||
http:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Accepts request from defined IP
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Accepts request from defined IP
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Accepts request from defined IP
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:------------------------------|:--------|:---------|
|
||||
| `sourceRange` | List of allowed IPs (or ranges of allowed IPs by using CIDR notation). | | Yes |
|
||||
| `ipStrategy.depth` | Depth position of the IP to select in the `X-Forwarded-For` header (starting from the right).<br />0 means no depth.<br />If greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty<br /> If higher than 0, the `excludedIPs` options is not evaluated.<br /> More information about [`ipStrategy](#ipstrategy), and [`depth`](#example-of-depth--x-forwarded-for) below. | 0 | No |
|
||||
| `ipStrategy.excludedIPs` | Allows Traefik to scan the `X-Forwarded-For` header and select the first IP not in the list.<br />If `depth` is specified, `excludedIPs` is ignored.<br /> More information about [`ipStrategy](#ipstrategy), and [`excludedIPs`](#example-of-excludedips--x-forwarded-for) below. | | No |
|
||||
| `ipStrategy.ipv6Subnet` | If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. <br />More information about [`ipStrategy.ipv6Subnet`](#ipstrategyipv6subnet), and [`excludedIPs`](#example-of-excludedips--x-forwarded-for) below. | | No |
|
||||
|
||||
### ipStrategy
|
||||
|
||||
The `ipStrategy` option defines two parameters that configures how Traefik determines the client IP: `depth`, and `excludedIPs`.
|
||||
|
||||
If no strategy is set, the default behavior is to match `sourceRange` against the Remote address found in the request.
|
||||
|
||||
As a middleware, passlisting happens before the actual proxying to the backend takes place.
|
||||
In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, that is after it has already passed through passlisting.
|
||||
Therefore, during passlisting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be matched against `sourceRange`.
|
||||
|
||||
#### `ipStrategy.depth`
|
||||
|
||||
The `depth` option tells Traefik to use the `X-Forwarded-For` header and take the IP located at the `depth` position (starting from the right).
|
||||
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is less than or equal to 0.
|
||||
|
||||
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
### `ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside 0-128 interval
|
||||
|
||||
#### Example of ipv6Subnet
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| IP | ipv6Subnet | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
### Example of Depth & X-Forwarded-For
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||
|
||||
| X-Forwarded-For | depth | clientIP |
|
||||
|-----------------------------------------|---------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `1` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
|
||||
|
||||
### Example of ExcludedIPs & X-Forwarded-For
|
||||
|
||||
| X-Forwarded-For | excludedIPs | clientIP |
|
||||
|-----------------------------------------|-----------------------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"12.0.0.1,13.0.0.1"` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"10.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
|
@ -0,0 +1,51 @@
|
||||
---
|
||||
title: "Traefik Proxy Middleware Overview"
|
||||
description: "There are several available middleware in Traefik Proxy used to modify requests or headers, take charge of redirections, add authentication, and so on."
|
||||
---
|
||||
|
||||
# HTTP Middleware Overview
|
||||
|
||||
Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your service (or before the answer from the services are sent to the clients).
|
||||
|
||||
There are several available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
|
||||
|
||||
Middlewares that use the same protocol can be combined into chains to fit every scenario.
|
||||
|
||||
!!! warning "Provider Namespace"
|
||||
|
||||
Be aware of the concept of Providers Namespace described in the [Configuration Discovery](../../../install-configuration/providers/overview.md#provider-namespace) section.
|
||||
It also applies to Middlewares.
|
||||
|
||||
## Available HTTP Middlewares
|
||||
|
||||
| Middleware | Purpose | Area |
|
||||
|-------------------------------------------|---------------------------------------------------|-----------------------------|
|
||||
| [AddPrefix](addprefix.md) | Adds a Path Prefix | Path Modifier |
|
||||
| [BasicAuth](basicauth.md) | Adds Basic Authentication | Security, Authentication |
|
||||
| [Buffering](buffering.md) | Buffers the request/response | Request Lifecycle |
|
||||
| [Chain](chain.md) | Combines multiple pieces of middleware | Misc |
|
||||
| [CircuitBreaker](circuitbreaker.md) | Prevents calling unhealthy services | Request Lifecycle |
|
||||
| [Compress](compress.md) | Compresses the response | Content Modifier |
|
||||
| [ContentType](contenttype.md) | Handles Content-Type auto-detection | Misc |
|
||||
| [DigestAuth](digestauth.md) | Adds Digest Authentication | Security, Authentication |
|
||||
| [Errors](errorpages.md) | Defines custom error pages | Request Lifecycle |
|
||||
| [ForwardAuth](forwardauth.md) | Delegates Authentication | Security, Authentication |
|
||||
| [GrpcWeb](grpcweb.md) | Converts gRPC Web requests to HTTP/2 gRPC requests. | Request |
|
||||
| [Headers](headers.md) | Adds / Updates headers | Security |
|
||||
| [IPAllowList](ipallowlist.md) | Limits the allowed client IPs | Security, Request lifecycle |
|
||||
| [InFlightReq](inflightreq.md) | Limits the number of simultaneous connections | Security, Request lifecycle |
|
||||
| [PassTLSClientCert](passtlsclientcert.md) | Adds Client Certificates in a Header | Security |
|
||||
| [RateLimit](ratelimit.md) | Limits the call frequency | Security, Request lifecycle |
|
||||
| [RedirectScheme](redirectscheme.md) | Redirects based on scheme | Request lifecycle |
|
||||
| [RedirectRegex](redirectregex.md) | Redirects based on regex | Request lifecycle |
|
||||
| [ReplacePath](replacepath.md) | Changes the path of the request | Path Modifier |
|
||||
| [ReplacePathRegex](replacepathregex.md) | Changes the path of the request | Path Modifier |
|
||||
| [Retry](retry.md) | Automatically retries in case of error | Request lifecycle |
|
||||
| [StripPrefix](stripprefix.md) | Changes the path of the request | Path Modifier |
|
||||
| [StripPrefixRegex](stripprefixregex.md) | Changes the path of the request | Path Modifier |
|
||||
|
||||
## Community Middlewares
|
||||
|
||||
Please take a look at the community-contributed plugins in the [plugin catalog](https://plugins.traefik.io/plugins).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,366 @@
|
||||
---
|
||||
title: "Traefik PassTLSClientCert Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, the PassTLSClientCert adds selected data from passed client TLS certificates to headers. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `passTLSClientCert` middleware adds the selected data from the passed client TLS certificate to a header.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
Pass the pem in the `X-Forwarded-Tls-Client-Cert` header:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
http:
|
||||
middlewares:
|
||||
test-passtlsclientcert:
|
||||
passTLSClientCert:
|
||||
pem: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-passtlsclientcert.passTLSClientCert]
|
||||
pem = true
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Pass the pem in the `X-Forwarded-Tls-Client-Cert` header
|
||||
{
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-passtlsclientcert
|
||||
spec:
|
||||
passTLSClientCert:
|
||||
pem: true
|
||||
```
|
||||
|
||||
??? example "Pass the pem in the `X-Forwarded-Tls-Client-Cert` header"
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
http:
|
||||
middlewares:
|
||||
test-passtlsclientcert:
|
||||
passTLSClientCert:
|
||||
info:
|
||||
notAfter: true
|
||||
notBefore: true
|
||||
sans: true
|
||||
subject:
|
||||
country: true
|
||||
province: true
|
||||
locality: true
|
||||
organization: true
|
||||
organizationalUnit: true
|
||||
commonName: true
|
||||
serialNumber: true
|
||||
domainComponent: true
|
||||
issuer:
|
||||
country: true
|
||||
province: true
|
||||
locality: true
|
||||
organization: true
|
||||
commonName: true
|
||||
serialNumber: true
|
||||
domainComponent: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-passtlsclientcert.passTLSClientCert]
|
||||
[http.middlewares.test-passtlsclientcert.passTLSClientCert.info]
|
||||
notAfter = true
|
||||
notBefore = true
|
||||
sans = true
|
||||
[http.middlewares.test-passtlsclientcert.passTLSClientCert.info.subject]
|
||||
country = true
|
||||
province = true
|
||||
locality = true
|
||||
organization = true
|
||||
organizationalUnit = true
|
||||
commonName = true
|
||||
serialNumber = true
|
||||
domainComponent = true
|
||||
[http.middlewares.test-passtlsclientcert.passTLSClientCert.info.issuer]
|
||||
country = true
|
||||
province = true
|
||||
locality = true
|
||||
organization = true
|
||||
commonName = true
|
||||
serialNumber = true
|
||||
domainComponent = true
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.serialnumber=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
{
|
||||
//...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-passtlsclientcert
|
||||
spec:
|
||||
passTLSClientCert:
|
||||
info:
|
||||
notAfter: true
|
||||
notBefore: true
|
||||
sans: true
|
||||
subject:
|
||||
country: true
|
||||
province: true
|
||||
locality: true
|
||||
organization: true
|
||||
organizationalUnit: true
|
||||
commonName: true
|
||||
serialNumber: true
|
||||
domainComponent: true
|
||||
issuer:
|
||||
country: true
|
||||
province: true
|
||||
locality: true
|
||||
organization: true
|
||||
commonName: true
|
||||
serialNumber: true
|
||||
domainComponent: true
|
||||
```
|
||||
|
||||
## General Information
|
||||
|
||||
`passTLSClientCert` can add two headers to the request:
|
||||
|
||||
- `X-Forwarded-Tls-Client-Cert` that contains the pem.
|
||||
- `X-Forwarded-Tls-Client-Cert-Info` that contains all the selected certificate information in an escaped string.
|
||||
|
||||
!!! info
|
||||
|
||||
- `X-Forwarded-Tls-Client-Cert-Info` header value is a string that has been escaped in order to be a valid URL query.
|
||||
- These options only work accordingly to the MutualTLS configuration. i.e, only the certificates that match the `clientAuth.clientAuthType` policy are passed.
|
||||
|
||||
??? example "Example of a complete certificate and explaining each of the middleware options"
|
||||
|
||||
```txt
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=org, DC=cheese, O=Cheese, O=Cheese 2, OU=Simple Signing Section, OU=Simple Signing Section 2, CN=Simple Signing CA, CN=Simple Signing CA 2, C=FR, C=US, L=TOULOUSE, L=LYON, ST=Signing State, ST=Signing State 2/emailAddress=simple@signing.com/emailAddress=simple2@signing.com
|
||||
Validity
|
||||
Not Before: Dec 6 11:10:16 2018 GMT
|
||||
Not After : Dec 5 11:10:16 2020 GMT
|
||||
Subject: DC=org, DC=cheese, O=Cheese, O=Cheese 2, OU=Simple Signing Section, OU=Simple Signing Section 2, CN=*.example.org, CN=*.example.com, C=FR, C=US, L=TOULOUSE, L=LYON, ST=Cheese org state, ST=Cheese com statemailAddress=cert@example.org/emailAddress=cert@sexample.com
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:de:77:fa:8d:03:70:30:39:dd:51:1b:cc:60:db:
|
||||
a9:5a:13:b1:af:fe:2c:c6:38:9b:88:0a:0f:8e:d9:
|
||||
1b:a1:1d:af:0d:66:e4:13:5b:bc:5d:36:92:d7:5e:
|
||||
d0:fa:88:29:d3:78:e1:81:de:98:b2:a9:22:3f:bf:
|
||||
8a:af:12:92:63:d4:a9:c3:f2:e4:7e:d2:dc:a2:c5:
|
||||
39:1c:7a:eb:d7:12:70:63:2e:41:47:e0:f0:08:e8:
|
||||
dc:be:09:01:ec:28:09:af:35:d7:79:9c:50:35:d1:
|
||||
6b:e5:87:7b:34:f6:d2:31:65:1d:18:42:69:6c:04:
|
||||
11:83:fe:44:ae:90:92:2d:0b:75:39:57:62:e6:17:
|
||||
2f:47:2b:c7:53:dd:10:2d:c9:e3:06:13:d2:b9:ba:
|
||||
63:2e:3c:7d:83:6b:d6:89:c9:cc:9d:4d:bf:9f:e8:
|
||||
a3:7b:da:c8:99:2b:ba:66:d6:8e:f8:41:41:a0:c9:
|
||||
d0:5e:c8:11:a4:55:4a:93:83:87:63:04:63:41:9c:
|
||||
fb:68:04:67:c2:71:2f:f2:65:1d:02:5d:15:db:2c:
|
||||
d9:04:69:85:c2:7d:0d:ea:3b:ac:85:f8:d4:8f:0f:
|
||||
c5:70:b2:45:e1:ec:b2:54:0b:e9:f7:82:b4:9b:1b:
|
||||
2d:b9:25:d4:ab:ca:8f:5b:44:3e:15:dd:b8:7f:b7:
|
||||
ee:f9
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication, TLS Web Client Authentication
|
||||
X509v3 Subject Key Identifier:
|
||||
94:BA:73:78:A2:87:FB:58:28:28:CF:98:3B:C2:45:70:16:6E:29:2F
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:1E:52:A2:E8:54:D5:37:EB:D5:A8:1D:E4:C2:04:1D:37:E2:F7:70:03
|
||||
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:*.example.org, DNS:*.example.net, DNS:*.example.com, IP Address:10.0.1.0, IP Address:10.0.1.2, email:test@example.org, email:test@example.net
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
76:6b:05:b0:0e:34:11:b1:83:99:91:dc:ae:1b:e2:08:15:8b:
|
||||
16:b2:9b:27:1c:02:ac:b5:df:1b:d0:d0:75:a4:2b:2c:5c:65:
|
||||
ed:99:ab:f7:cd:fe:38:3f:c3:9a:22:31:1b:ac:8c:1c:c2:f9:
|
||||
5d:d4:75:7a:2e:72:c7:85:a9:04:af:9f:2a:cc:d3:96:75:f0:
|
||||
8e:c7:c6:76:48:ac:45:a4:b9:02:1e:2f:c0:15:c4:07:08:92:
|
||||
cb:27:50:67:a1:c8:05:c5:3a:b3:a6:48:be:eb:d5:59:ab:a2:
|
||||
1b:95:30:71:13:5b:0a:9a:73:3b:60:cc:10:d0:6a:c7:e5:d7:
|
||||
8b:2f:f9:2e:98:f2:ff:81:14:24:09:e3:4b:55:57:09:1a:22:
|
||||
74:f1:f6:40:13:31:43:89:71:0a:96:1a:05:82:1f:83:3a:87:
|
||||
9b:17:25:ef:5a:55:f2:2d:cd:0d:4d:e4:81:58:b6:e3:8d:09:
|
||||
62:9a:0c:bd:e4:e5:5c:f0:95:da:cb:c7:34:2c:34:5f:6d:fc:
|
||||
60:7b:12:5b:86:fd:df:21:89:3b:48:08:30:bf:67:ff:8c:e6:
|
||||
9b:53:cc:87:36:47:70:40:3b:d9:90:2a:d2:d2:82:c6:9c:f5:
|
||||
d1:d8:e0:e6:fd:aa:2f:95:7e:39:ac:fc:4e:d4:ce:65:b3:ec:
|
||||
c6:98:8a:31
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGWjCCBUKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCCAYQxEzARBgoJkiaJk/Is
|
||||
ZAEZFgNvcmcxFjAUBgoJkiaJk/IsZAEZFgZjaGVlc2UxDzANBgNVBAoMBkNoZWVz
|
||||
ZTERMA8GA1UECgwIQ2hlZXNlIDIxHzAdBgNVBAsMFlNpbXBsZSBTaWduaW5nIFNl
|
||||
Y3Rpb24xITAfBgNVBAsMGFNpbXBsZSBTaWduaW5nIFNlY3Rpb24gMjEaMBgGA1UE
|
||||
AwwRU2ltcGxlIFNpZ25pbmcgQ0ExHDAaBgNVBAMME1NpbXBsZSBTaWduaW5nIENB
|
||||
IDIxCzAJBgNVBAYTAkZSMQswCQYDVQQGEwJVUzERMA8GA1UEBwwIVE9VTE9VU0Ux
|
||||
DTALBgNVBAcMBExZT04xFjAUBgNVBAgMDVNpZ25pbmcgU3RhdGUxGDAWBgNVBAgM
|
||||
D1NpZ25pbmcgU3RhdGUgMjEhMB8GCSqGSIb3DQEJARYSc2ltcGxlQHNpZ25pbmcu
|
||||
Y29tMSIwIAYJKoZIhvcNAQkBFhNzaW1wbGUyQHNpZ25pbmcuY29tMB4XDTE4MTIw
|
||||
NjExMTAxNloXDTIwMTIwNTExMTAxNlowggF2MRMwEQYKCZImiZPyLGQBGRYDb3Jn
|
||||
MRYwFAYKCZImiZPyLGQBGRYGY2hlZXNlMQ8wDQYDVQQKDAZDaGVlc2UxETAPBgNV
|
||||
BAoMCENoZWVzZSAyMR8wHQYDVQQLDBZTaW1wbGUgU2lnbmluZyBTZWN0aW9uMSEw
|
||||
HwYDVQQLDBhTaW1wbGUgU2lnbmluZyBTZWN0aW9uIDIxFTATBgNVBAMMDCouY2hl
|
||||
ZXNlLm9yZzEVMBMGA1UEAwwMKi5jaGVlc2UuY29tMQswCQYDVQQGEwJGUjELMAkG
|
||||
A1UEBhMCVVMxETAPBgNVBAcMCFRPVUxPVVNFMQ0wCwYDVQQHDARMWU9OMRkwFwYD
|
||||
VQQIDBBDaGVlc2Ugb3JnIHN0YXRlMRkwFwYDVQQIDBBDaGVlc2UgY29tIHN0YXRl
|
||||
MR4wHAYJKoZIhvcNAQkBFg9jZXJ0QGNoZWVzZS5vcmcxHzAdBgkqhkiG9w0BCQEW
|
||||
EGNlcnRAc2NoZWVzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||
AQDed/qNA3AwOd1RG8xg26laE7Gv/izGOJuICg+O2RuhHa8NZuQTW7xdNpLXXtD6
|
||||
iCnTeOGB3piyqSI/v4qvEpJj1KnD8uR+0tyixTkceuvXEnBjLkFH4PAI6Ny+CQHs
|
||||
KAmvNdd5nFA10Wvlh3s09tIxZR0YQmlsBBGD/kSukJItC3U5V2LmFy9HK8dT3RAt
|
||||
yeMGE9K5umMuPH2Da9aJycydTb+f6KN72siZK7pm1o74QUGgydBeyBGkVUqTg4dj
|
||||
BGNBnPtoBGfCcS/yZR0CXRXbLNkEaYXCfQ3qO6yF+NSPD8VwskXh7LJUC+n3grSb
|
||||
Gy25JdSryo9bRD4V3bh/t+75AgMBAAGjgeAwgd0wDgYDVR0PAQH/BAQDAgWgMAkG
|
||||
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
|
||||
BBSUunN4oof7WCgoz5g7wkVwFm4pLzAfBgNVHSMEGDAWgBQeUqLoVNU369WoHeTC
|
||||
BB034vdwAzBhBgNVHREEWjBYggwqLmNoZWVzZS5vcmeCDCouY2hlZXNlLm5ldIIM
|
||||
Ki5jaGVlc2UuY29thwQKAAEAhwQKAAECgQ90ZXN0QGNoZWVzZS5vcmeBD3Rlc3RA
|
||||
Y2hlZXNlLm5ldDANBgkqhkiG9w0BAQUFAAOCAQEAdmsFsA40EbGDmZHcrhviCBWL
|
||||
FrKbJxwCrLXfG9DQdaQrLFxl7Zmr983+OD/DmiIxG6yMHML5XdR1ei5yx4WpBK+f
|
||||
KszTlnXwjsfGdkisRaS5Ah4vwBXEBwiSyydQZ6HIBcU6s6ZIvuvVWauiG5UwcRNb
|
||||
CppzO2DMENBqx+XXiy/5Lpjy/4EUJAnjS1VXCRoidPH2QBMxQ4lxCpYaBYIfgzqH
|
||||
mxcl71pV8i3NDU3kgVi2440JYpoMveTlXPCV2svHNCw0X238YHsSW4b93yGJO0gI
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:------------------------------------------------------------|:--------|:---------|
|
||||
| `pem` | Fills the `X-Forwarded-Tls-Client-Cert` header with the certificate information.<br /> More information [here](#pem). | false | No |
|
||||
| `info.serialNumber` | Add the `Serial Number` of the certificate.<br /> More information about `info` [here](#info). | false | No |
|
||||
| `info.notAfter` | Add the `Not After` information from the `Validity` part. <br /> More information about `info` [here](#info). | false | No |
|
||||
| `info.notBefore` | Add the `Not Before` information from the `Validity` part. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.sans` | Add the `Subject Alternative Name` information from the `Subject Alternative Name` part. <br /> More information about `info` [here](#info). | false | No |
|
||||
| `info.subject` | The `info.subject` selects the specific client certificate subject details you want to add to the `X-Forwarded-Tls-Client-Cert-Info` header. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.country` | Add the `country` information into the subject.<br /> The data is taken from the subject part with the `C` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.province` | Add the `province` information into the subject.<br /> The data is taken from the subject part with the `ST` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.locality` | Add the `locality` information into the subject.<br /> The data is taken from the subject part with the `L` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.organization` | Add the `organization` information into the subject.<br /> The data is taken from the subject part with the `O` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.organizationalUnit` | Add the `organizationalUnit` information into the subject.<br /> The data is taken from the subject part with the `OU` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.subject.commonName` | Add the `commonName` information into the subject.<br /> The data is taken from the subject part with the `CN` key.| false | No |
|
||||
| `info.subject.serialNumber` | Add the `serialNumber` information into the subject.<br /> The data is taken from the subject part with the `SN` key.| false | No |
|
||||
| `info.subject.domainComponent` | Add the `domainComponent` information into the subject.<br />The data is taken from the subject part with the `DC` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer` | The `info.issuer` selects the specific client certificate issuer details you want to add to the `X-Forwarded-Tls-Client-Cert-Info` header. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.country` | Add the `country` information into the issuer.<br /> The data is taken from the issuer part with the `C` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.province` | Add the `province` information into the issuer.<br />The data is taken from the issuer part with the `ST` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.locality` | Add the `locality` information into the issuer.<br /> The data is taken from the issuer part with the `L` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.organization` | Add the `organization` information into the issuer.<br /> The data is taken from the issuer part with the `O` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.commonName` |Add the `commonName` information into the issuer.<br /> The data is taken from the issuer part with the `CN` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.serialNumber` |Add the `serialNumber` information into the issuer.<br /> The data is taken from the issuer part with the `SN` key. <br />More information about `info` [here](#info). | false | No |
|
||||
| `info.issuer.domainComponent` | Add the `domainComponent` information into the issuer.<br /> The data is taken from the issuer part with the `DC` key. <br />More information about `info` [here](#info). | false | No |
|
||||
|
||||
### pem
|
||||
|
||||
#### Data Format
|
||||
|
||||
The delimiters and `\n` will be removed.
|
||||
If there are more than one certificate, they are separated by a "`,`".
|
||||
|
||||
#### Header size
|
||||
|
||||
The `X-Forwarded-Tls-Client-Cert` header value could exceed the web server header size limit
|
||||
|
||||
The header size limit of web servers is commonly between 4kb and 8kb.
|
||||
If that turns out to be a problem, and if reconfiguring the server to allow larger headers is not an option,
|
||||
one can alleviate the problem by selecting only the interesting parts of the cert,
|
||||
through the use of the `info` options described below. (And by setting `pem` to false).
|
||||
|
||||
### info
|
||||
|
||||
The `info` option selects the specific client certificate details you want to add to the `X-Forwarded-Tls-Client-Cert-Info` header.
|
||||
|
||||
#### Data Format
|
||||
|
||||
The value of the header is an escaped concatenation of all the selected certificate details.
|
||||
Unless specified otherwise, all the header values examples are shown unescaped, for readability.
|
||||
|
||||
If there are more than one certificate, they are separated by a `,`.
|
||||
|
||||
The following example shows such a concatenation, when all the available fields are selected:
|
||||
|
||||
```text
|
||||
Subject="DC=org,DC=cheese,C=FR,C=US,ST=Cheese org state,ST=Cheese com state,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=*.example.com";Issuer="DC=org,DC=cheese,C=FR,C=US,ST=Signing State,ST=Signing State 2,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=Simple Signing CA 2";NB="1544094616";NA="1607166616";SAN="*.example.org,*.example.net,*.example.com,test@example.org,test@example.net,10.0.1.0,10.0.1.2"
|
||||
```
|
@ -0,0 +1,150 @@
|
||||
---
|
||||
title: "Traefik RateLimit Documentation"
|
||||
description: "Traefik Proxy's HTTP RateLimit middleware ensures Services receive fair amounts of requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `rateLimit` middleware ensures that services will receive a *fair* amount of requests, and allows you to define what fair is.
|
||||
|
||||
It is based on a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) implementation.
|
||||
In this analogy, the `average` and `period` parameters define the **rate** at which the bucket refills, and the `burst` is the size (volume) of the bucket
|
||||
|
||||
## Rate and Burst
|
||||
|
||||
The rate is defined by dividing `average` by `period`.
|
||||
For a rate below 1 req/s, define a `period` larger than a second
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Here, an average of 100 requests per second is allowed.
|
||||
# In addition, a burst of 200 requests is allowed.
|
||||
http:
|
||||
middlewares:
|
||||
test-ratelimit:
|
||||
rateLimit:
|
||||
average: 100
|
||||
burst: 200
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Here, an average of 100 requests per second is allowed.
|
||||
# In addition, a burst of 200 requests is allowed.
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ratelimit.rateLimit]
|
||||
average = 100
|
||||
burst = 200
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Here, an average of 100 requests per second is allowed.
|
||||
# In addition, a burst of 200 requests is allowed.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ratelimit.ratelimit.average=100"
|
||||
- "traefik.http.middlewares.test-ratelimit.ratelimit.burst=200"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Here, an average of 100 requests per second is allowed.
|
||||
// In addition, a burst of 200 requests is allowed.
|
||||
{
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-ratelimit.ratelimit.average=100",
|
||||
"traefik.http.middlewares.test-ratelimit.ratelimit.burst=50"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Here, an average of 100 requests per second is allowed.
|
||||
# In addition, a burst of 200 requests is allowed.
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ratelimit
|
||||
spec:
|
||||
rateLimit:
|
||||
average: 100
|
||||
burst: 200
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------|:-------------------------------------------------------|:--------|:---------|
|
||||
| `average` | Number of requests used to define the rate using the `period`.<br /> 0 means **no rate limiting**.<br />More information [here](#rate-and-burst). | 0 | No |
|
||||
| `period` | Period of time used to define the rate.<br />More information [here](#rate-and-burst). | 1s | No |
|
||||
| `burst` | Maximum number of requests allowed to go through at the very same moment.<br />More information [here](#rate-and-burst).| 1 | No |
|
||||
| `sourceCriterion.requestHost` | Whether to consider the request host as the source.<br />More information about `sourceCriterion`[here](#sourcecriterion). | false | No |
|
||||
| `sourceCriterion.requestHeaderName` | Name of the header used to group incoming requests.<br />More information about `sourceCriterion`[here](#sourcecriterion). | "" | No |
|
||||
| `sourceCriterion.ipStrategy.depth` | Depth position of the IP to select in the `X-Forwarded-For` header (starting from the right).<br />0 means no depth.<br />If greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty<br />If higher than 0, the `excludedIPs` options is not evaluated.<br />More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy`](#ipstrategy), and [`depth`](#sourcecriterionipstrategydepth) below. | 0 | No |
|
||||
| `sourceCriterion.ipStrategy.excludedIPs` | Allows scanning the `X-Forwarded-For` header and select the first IP not in the list.<br />If `depth` is specified, `excludedIPs` is ignored.<br />More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy`](#ipstrategy), and [`excludedIPs`](#sourcecriterionipstrategyexcludedips) below. | | No |
|
||||
| `sourceCriterion.ipStrategy.ipv6Subnet` | If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. <br />More information about [`sourceCriterion`](#sourcecriterion), [`ipStrategy.ipv6Subnet`](#sourcecriterionipstrategyipv6subnet) below. | | No |
|
||||
|
||||
### sourceCriterion
|
||||
|
||||
The `sourceCriterion` option defines what criterion is used to group requests as originating from a common source.
|
||||
If several strategies are defined at the same time, an error will be raised.
|
||||
If none are set, the default is to use the request's remote address field (as an `ipStrategy`).
|
||||
|
||||
### ipStrategy
|
||||
|
||||
The `ipStrategy` option defines three parameters that configures how Traefik determines the client IP: `depth`, `excludedIPs` and `ipv6Subnet`.
|
||||
|
||||
As a middleware, rate-limiting happens before the actual proxying to the backend takes place.
|
||||
In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, that is after it has already passed through rate-limiting.
|
||||
Therefore, during rate-limiting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be found and/or relied upon.
|
||||
|
||||
### `sourceCriterion.ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||
|
||||
#### Example of ipv6Subnet
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| `IP` | `ipv6Subnet` | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
### sourceCriterion.ipStrategy.depth
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||
|
||||
| `X-Forwarded-For` | `depth` | clientIP |
|
||||
|-----------------------------------------|---------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `1` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
|
||||
|
||||
### sourceCriterion.ipStrategy.excludedIPs
|
||||
|
||||
Contrary to what the name might suggest, this option is *not* about excluding an IP from the rate limiter, and therefore cannot be used to deactivate rate limiting for some IPs.
|
||||
|
||||
`excludedIPs` is meant to address two classes of somewhat distinct use-cases:
|
||||
|
||||
1. Distinguish IPs which are behind the same (set of) reverse-proxies so that each of them contributes, independently to the others, to its own rate-limit "bucket" (cf the [token bucket](https://en.wikipedia.org/wiki/Token_bucket)).
|
||||
In this case, `excludedIPs` should be set to match the list of `X-Forwarded-For IPs` that are to be excluded, in order to find the actual clientIP.
|
||||
|
||||
Example to use each IP as a distinct source:
|
||||
|
||||
| X-Forwarded-For | excludedIPs | clientIP |
|
||||
|--------------------------------|-----------------------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1"` | `"11.0.0.1,12.0.0.1"` | `"10.0.0.1"` |
|
||||
| `"10.0.0.2,11.0.0.1,12.0.0.1"` | `"11.0.0.1,12.0.0.1"` | `"10.0.0.2"` |
|
||||
|
||||
2. Group together a set of IPs (also behind a common set of reverse-proxies) so that they are considered the same source, and all contribute to the same rate-limit bucket.
|
||||
|
||||
Example to group IPs together as same source:
|
||||
|
||||
| X-Forwarded-For | excludedIPs | clientIP |
|
||||
|--------------------------------|--------------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1"` | `"12.0.0.1"` | `"11.0.0.1"` |
|
||||
| `"10.0.0.2,11.0.0.1,12.0.0.1"` | `"12.0.0.1"` | `"11.0.0.1"` |
|
||||
| `"10.0.0.3,11.0.0.1,12.0.0.1"` | `"12.0.0.1"` | `"11.0.0.1"` |
|
@ -0,0 +1,88 @@
|
||||
---
|
||||
title: "Traefik RedirectRegex Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, RedirectRegex redirecting clients to different locations. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `RedirectRegex` redirects a request using regex matching and replacement.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Redirect with domain replacement
|
||||
http:
|
||||
middlewares:
|
||||
test-redirectregex:
|
||||
redirectRegex:
|
||||
regex: "^http://localhost/(.*)"
|
||||
replacement: "http://mydomain/${1}"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Redirect with domain replacement
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-redirectregex.redirectRegex]
|
||||
regex = "^http://localhost/(.*)"
|
||||
replacement = "http://mydomain/${1}"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Redirect with domain replacement
|
||||
# Note: all dollar signs need to be doubled for escaping.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
|
||||
- "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Redirect with domain replacement
|
||||
// Note: all dollar signs need to be doubled for escaping.
|
||||
{
|
||||
// ...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
|
||||
"traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Redirect with domain replacement
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-redirectregex
|
||||
spec:
|
||||
redirectRegex:
|
||||
regex: ^http://localhost/(.*)
|
||||
replacement: http://mydomain/${1}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `regex` | The `regex` option is the regular expression to match and capture elements from the request URL.| "" | Yes |
|
||||
| `permanent` | Enable a permanent redirection. | false | No |
|
||||
| `replacement` | The `replacement` option defines how to modify the URL to have the new target URL..<br /> `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax. | "" | No |
|
||||
|
||||
### `regex`
|
||||
|
||||
The `regex` option is the regular expression to match and capture elements from the request URL.
|
||||
|
||||
!!! tip
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`.
|
||||
|
||||
### `replacement`
|
||||
|
||||
The `replacement` option defines how to modify the URL to have the new target URL.
|
||||
|
||||
!!! warning
|
||||
|
||||
Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,74 @@
|
||||
---
|
||||
title: "Traefik RedirectScheme Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, RedirectScheme redirects clients to different schemes/ports. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `RedirectScheme` middleware redirects the request if the request scheme is different from the configured scheme.
|
||||
|
||||
!!! warning "When behind another reverse-proxy"
|
||||
|
||||
When there is at least one other reverse-proxy between the client and Traefik,
|
||||
the other reverse-proxy (i.e. the last hop) needs to be a [trusted](../../../install-configuration/entrypoints.md#configuration-options) one.
|
||||
|
||||
Otherwise, Traefik would clean up the X-Forwarded headers coming from this last hop,
|
||||
and as the RedirectScheme middleware relies on them to determine the scheme used,
|
||||
it would not function as intended.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Redirect to https
|
||||
http:
|
||||
middlewares:
|
||||
test-redirectscheme:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
permanent: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Redirect to https
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-redirectscheme.redirectScheme]
|
||||
scheme = "https"
|
||||
permanent = true
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Redirect to https
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Redirect to https
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Redirect to https
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-redirectscheme
|
||||
spec:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
permanent: true
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|----------------------------------------------------------|:--------|:---------|
|
||||
| `scheme` | Scheme of the new URL. | "" | Yes |
|
||||
| `permanent` | Enable a permanent redirection. | false | No |
|
||||
| `port` | Port of the new URL.<br />Set a string, **not** a numeric value. | "" | No |
|
@ -0,0 +1,60 @@
|
||||
---
|
||||
title: "Traefik ReplacePath Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, ReplacePath updates paths before forwarding requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `replacePath` middleware will:
|
||||
|
||||
- Replace the actual path with the specified one.
|
||||
- Store the original path in a `X-Replaced-Path` header
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Replace the path with /foo
|
||||
http:
|
||||
middlewares:
|
||||
test-replacepath:
|
||||
replacePath:
|
||||
path: "/foo"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Replace the path with /foo
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-replacepath.replacePath]
|
||||
path = "/foo"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Replace the path with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Replace the path with /foo
|
||||
{
|
||||
// ...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Replace the path with /foo
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-replacepath
|
||||
spec:
|
||||
replacePath:
|
||||
path: "/foo"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description |
|
||||
|:------|:------------|
|
||||
| `path` | The `path` option defines the path to use as replacement in the request URL. |
|
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Traefik ReplacePathRegex Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, ReplacePathRegex updates paths before forwarding requests, using a regex. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `replacePathRegex` middleware will:
|
||||
|
||||
- Replace the matching path with the specified one.
|
||||
- Store the original path in an `X-Replaced-Path` header
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Replace path with regex
|
||||
http:
|
||||
middlewares:
|
||||
test-replacepathregex:
|
||||
replacePathRegex:
|
||||
regex: "^/foo/(.*)"
|
||||
replacement: "/bar/$1"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Replace path with regex
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-replacepathregex.replacePathRegex]
|
||||
regex = "^/foo/(.*)"
|
||||
replacement = "/bar/$1"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Replace path with regex
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-replacepathregex
|
||||
spec:
|
||||
replacePathRegex:
|
||||
regex: "^/foo/(.*)"
|
||||
replacement: "/bar/$1"
|
||||
```
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Replace path with regex
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)"
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$$1"
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Replace path with regex
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)"
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$1"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `regex` | Regular expression to match and capture the path from the request URL. | | Yes |
|
||||
| `replacement` | Replacement path format, which can include captured variables.<br /> `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax. | | No
|
||||
|
||||
!!! tip
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`.
|
@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Traefik HTTP Retry Documentation"
|
||||
description: "Configure Traefik Proxy's HTTP Retry middleware, so you can retry requests to a backend server until it succeeds. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `retry` middleware retries requests a given number of times to a backend server if that server does not reply.
|
||||
As soon as the server answers, the middleware stops retrying, regardless of the response status.
|
||||
|
||||
The Retry middleware has an optional configuration to enable an exponential backoff.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Retry 4 times with exponential backoff
|
||||
http:
|
||||
middlewares:
|
||||
test-retry:
|
||||
retry:
|
||||
attempts: 4
|
||||
initialInterval: 100ms
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Retry 4 times with exponential backoff
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-retry.retry]
|
||||
attempts = 4
|
||||
initialInterval = "100ms"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Retry 4 times with exponential backoff
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-retry.retry.attempts=4"
|
||||
- "traefik.http.middlewares.test-retry.retry.initialinterval=100ms"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Retry 4 times with exponential backoff
|
||||
|
||||
{
|
||||
// ...
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-retry.retry.attempts=4",
|
||||
"traefik.http.middlewares.test-retry.retry.initialinterval=100ms"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Retry 4 times with exponential backoff
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-retry
|
||||
spec:
|
||||
retry:
|
||||
attempts: 4
|
||||
initialInterval: 100ms
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|:--------|:---------|
|
||||
| `attempts` | number of times the request should be retried. | | Yes |
|
||||
| `initialInterval` | First wait time in the exponential backoff series. <br />The maximum interval is calculated as twice the `initialInterval`. <br /> If unspecified, requests will be retried immediately.<br /> Defined in seconds or as a valid duration format, see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration). | 0 | No |
|
@ -0,0 +1,66 @@
|
||||
---
|
||||
title: "Traefik StripPrefix Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, StripPrefix removes prefixes from paths before forwarding requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `stripPrefix` middleware strips the matching path prefix and stores it in an `X-Forwarded-Prefix` header.
|
||||
|
||||
!!! tip
|
||||
|
||||
Use a `StripPrefix` middleware if your backend listens on the root path (`/`) but should be exposed on a specific prefix.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
http:
|
||||
middlewares:
|
||||
test-stripprefix:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- "/foobar"
|
||||
- "/fiibar"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-stripprefix.stripPrefix]
|
||||
prefixes = ["/foobar", "/fiibar"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Strip prefix /foobar and /fiibar
|
||||
{
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-stripprefix
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /foobar
|
||||
- /fiibar
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:--------------------------------------------------------------|:--------|:---------|
|
||||
| `prefixes` | List of prefixes to strip from the request URL.<br />If your backend is serving assets (for example, images or JavaScript files), it can use the `X-Forwarded-Prefix` header to construct relative URLs. | [] | No |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,70 @@
|
||||
---
|
||||
title: "Traefik StripPrefixRegex Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, StripPrefixRegex removes prefixes from paths before forwarding requests, using regex. Read the technical documentation."
|
||||
---
|
||||
|
||||
The `stripPrefixRegex` middleware strips the matching path prefix and stores it in an `X-Forwarded-Prefix` header.
|
||||
|
||||
!!! tip
|
||||
|
||||
Use a `stripPrefixRegex` middleware if your backend listens on the root path (`/`) but should be exposed on a specific prefix.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-stripprefixregex:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-stripprefixregex.stripPrefixRegex]
|
||||
regex = ["/foo/[a-z0-9]+/[0-9]+/"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```yaml tab="Tags"
|
||||
{
|
||||
//..
|
||||
"Tags" : [
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
|
||||
]
|
||||
}
|
||||
-
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-stripprefixregex
|
||||
spec:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
|
||||
| `regex` | List of regular expressions to match the path prefix from the request URL.<br /> For instance, `/products` also matches `/products/shoes` and `/products/shirts`.<br />More information [here](#regex). | | No |
|
||||
|
||||
### regex
|
||||
|
||||
If your backend is serving assets (for example, images or JavaScript files), it can use the `X-Forwarded-Prefix` header to construct relative URLs.
|
||||
Using the previous example, the backend should return `/products/shoes/image.png` (and not `/images.png`, which Traefik would likely not be able to associate with the same backend).
|
||||
|
||||
!!! tip
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`.
|
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: "Per-Router Observability"
|
||||
description: "You can disable access logs, metrics, and tracing for a specific entrypoint attached to a HTTP Router. Read the technical documentation."
|
||||
---
|
||||
|
||||
Traefik's observability features include logs, access logs, metrics, and tracing. You can configure these options globally or at more specific levels, such as per router or per entry point.
|
||||
|
||||
By default, the router observability configuration is inherited from the attached EntryPoints and can be configured with the observability [options](../../../install-configuration/entrypoints.md#configuration-options)).
|
||||
However, a router defining its own observability configuration will opt-out from these defaults.
|
||||
|
||||
!!! info
|
||||
To enable router-level observability, you must first enable access-logs, tracing, and metrics.
|
||||
|
||||
When metrics layers are not enabled with the `addEntryPointsLabels`, `addRoutersLabels` and/or `addServicesLabels` options,
|
||||
enabling metrics for a router will not enable them.
|
||||
|
||||
!!! warning "AddInternals option"
|
||||
|
||||
By default, and for any type of signal (access-logs, metrics and tracing),
|
||||
Traefik disables observability for internal resources.
|
||||
The observability options described below cannot interfere with the `AddInternals` ones,
|
||||
and will be ignored.
|
||||
|
||||
For instance, if a router exposes the `api@internal` service and `metrics.AddInternals` is false,
|
||||
it will never produces metrics, even if the router observability configuration enables metrics.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
routers:
|
||||
my-router:
|
||||
rule: "Path(`/foo`)"
|
||||
service: service-foo
|
||||
observability:
|
||||
metrics: false
|
||||
accessLogs: false
|
||||
tracing: false
|
||||
```
|
||||
|
||||
```yaml tab="Structured (TOML)"
|
||||
[http.routers.my-router]
|
||||
rule = "Path(`/foo`)"
|
||||
service = "service-foo"
|
||||
|
||||
[http.routers.my-router.observability]
|
||||
metrics = false
|
||||
accessLogs = false
|
||||
tracing = false
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.routers.my-router.rule=Path(`/foo`)"
|
||||
- "traefik.http.routers.my-router.service=service-foo"
|
||||
- "traefik.http.routers.my-router.observability.metrics=false"
|
||||
- "traefik.http.routers.my-router.observability.accessLogs=false"
|
||||
- "traefik.http.routers.my-router.observability.tracing=false"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.routers.my-router.rule=Path(`/foo`)",
|
||||
"traefik.http.routers.my-router.service=service-foo",
|
||||
"traefik.http.routers.my-router.observability.metrics=false",
|
||||
"traefik.http.routers.my-router.observability.accessLogs=false",
|
||||
"traefik.http.routers.my-router.observability.tracing=false"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|:--------|:---------|
|
||||
| `accessLogs` | The `accessLogs` option controls whether the router will produce access-logs. | `true` | No |
|
||||
| `metrics` | The `metrics` option controls whether the router will produce metrics. | `true` | No |
|
||||
| `tracing` | The `tracing` option controls whether the router will produce traces. | `true` | No |
|
@ -0,0 +1,291 @@
|
||||
---
|
||||
title: "Traefik HTTP Routers Rules & Priority Documentation"
|
||||
description: "In Traefik Proxy, an HTTP router is in charge of connecting incoming requests to the Services that can handle them. Read the technical documentation."
|
||||
---
|
||||
|
||||
An HTTP router is in charge of connecting incoming requests to the services that can handle them. Traefik allows you to define your matching rules and [prioritize](#priority-calculation) the routes.
|
||||
|
||||
## Rules
|
||||
|
||||
Rules are a set of matchers configured with values, that determine if a particular request matches a specific criteria.
|
||||
If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.
|
||||
|
||||
- The character `@` is not authorized in the router name.
|
||||
- To set the value of a rule, use [backticks](https://en.wiktionary.org/wiki/backtick) ` or escaped double-quotes ``\"``.
|
||||
- Single quotes ' are not accepted since the values are [Go's String Literals](https://golang.org/ref/spec#String_literals).
|
||||
- Regular Expressions:
|
||||
- Matchers that accept a regexp as their value use a [Go](https://golang.org/pkg/regexp/) flavored syntax.
|
||||
- The usual `AND` (&&) and `OR` (||) logical operators can be used, with the expected precedence rules, as well as parentheses to express complex rules.
|
||||
- The `NOT` (!) operator allows you to invert the matcher.
|
||||
|
||||
The table below lists all the available matchers:
|
||||
|
||||
| Matcher | Description |
|
||||
|-----------------------------------------------------------------|:-------------------------------------------------------------------------------|
|
||||
| [```Header(`key`, `value`)```](#header-and-headerregexp) | Matches requests containing a header named `key` set to `value`. |
|
||||
| [```HeaderRegexp(`key`, `regexp`)```](#header-and-headerregexp) | Matches requests containing a header named `key` matching `regexp`. |
|
||||
| [```Host(`domain`)```](#host-and-hostregexp) | Matches requests host set to `domain`. |
|
||||
| [```HostRegexp(`regexp`)```](#host-and-hostregexp) | Matches requests host matching `regexp`. |
|
||||
| [```Method(`method`)```](#method) | Matches requests method set to `method`. |
|
||||
| [```Path(`path`)```](#path-pathprefix-and-pathregexp) | Matches requests path set to `path`. |
|
||||
| [```PathPrefix(`prefix`)```](#path-pathprefix-and-pathregexp) | Matches requests path prefix set to `prefix`. |
|
||||
| [```PathRegexp(`regexp`)```](#path-pathprefix-and-pathregexp) | Matches request path using `regexp`. |
|
||||
| [```Query(`key`, `value`)```](#query-and-queryregexp) | Matches requests query parameters named `key` set to `value`. |
|
||||
| [```QueryRegexp(`key`, `regexp`)```](#query-and-queryregexp) | Matches requests query parameters named `key` matching `regexp`. |
|
||||
| [```ClientIP(`ip`)```](#clientip) | Matches requests client IP using `ip`. It accepts IPv4, IPv6 and CIDR formats. |
|
||||
|
||||
### Header and HeaderRegexp
|
||||
|
||||
The `Header` and `HeaderRegexp` matchers allow matching requests that contain specific header.
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match requests with a `Content-Type` header set to `application/yaml`.| ```Header(`Content-Type`, `application/yaml`)``` |
|
||||
| Match requests with a `Content-Type` header set to either `application/json` or `application/yaml`. | ```HeaderRegexp(`Content-Type`, `^application/(json\|yaml)$`)``` |
|
||||
| Match headers [case-insensitively](https://en.wikipedia.org/wiki/Case_sensitivity). | ```HeaderRegexp(`Content-Type`, `(?i)^application/(json\|yaml)$`)``` |
|
||||
|
||||
### Host and HostRegexp
|
||||
|
||||
The `Host` and `HostRegexp` matchers allow matching requests that are targeted to a given host.
|
||||
|
||||
These matchers do not support non-ASCII characters, use punycode encoded values ([rfc 3492](https://tools.ietf.org/html/rfc3492)) to match such domains.
|
||||
|
||||
If no `Host` is set in the request URL (for example, it's an IP address), these matchers will look at the `Host` header.
|
||||
|
||||
These matchers will match the request's host in lowercase.
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match requests with `Host` set to `example.com`. | ```Host(`example.com`)``` |
|
||||
| Match requests sent to any subdomain of `example.com`. | ```HostRegexp(`^.+\.example\.com$`)``` |
|
||||
| Match requests with `Host` set to either `example.com` or `example.org`. | ```HostRegexp(`^example\.(com\|org)$`)``` |
|
||||
| Match `Host` [case-insensitively](https://en.wikipedia.org/wiki/Case_sensitivity). | ```HostRegexp(`(?i)^example\.(com\|org)$`)``` |
|
||||
|
||||
### Method
|
||||
|
||||
The `Method` matchers allows matching requests sent based on their HTTP method (also known as request verb).
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match `OPTIONS` requests. | ```Method(`OPTIONS`)``` |
|
||||
|
||||
### Path, PathPrefix, and PathRegexp
|
||||
|
||||
These matchers allow matching requests based on their URL path.
|
||||
|
||||
For exact matches, use `Path` and its prefixed alternative `PathPrefix`, for regexp matches, use `PathRegexp`.
|
||||
|
||||
Path are always starting with a `/`, except for `PathRegexp`.
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match `/products` but neither `/products/shoes` nor `/products/`. | ```Path(`/products`)``` |
|
||||
| Match `/products` as well as everything under `/products`, such as `/products/shoes`, `/products/` but also `/products-for-sale`. | ```PathPrefix(`/products`)``` |
|
||||
| Match both `/products/shoes` and `/products/socks` with and ID like `/products/shoes/31`. | ```PathRegexp(`^/products/(shoes\|socks)/[0-9]+$`)``` |
|
||||
| Match requests with a path ending in either `.jpeg`, `.jpg` or `.png`. | ```PathRegexp(`\.(jpeg\|jpg\|png)$`)``` |
|
||||
| Match `/products` as well as everything under `/products`, such as `/products/shoes`, `/products/` but also `/products-for-sale`, [case-insensitively](https://en.wikipedia.org/wiki/Case_sensitivity). | ```HostRegexp(`(?i)^/products`)``` |
|
||||
|
||||
### Query and QueryRegexp
|
||||
|
||||
The `Query` and `QueryRegexp` matchers allow matching requests based on query parameters.
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match requests with a `mobile` query parameter set to `true`, such as in `/search?mobile=true`. | ```Query(`mobile`, `true`)``` |
|
||||
| Match requests with a query parameter `mobile` that has no value, such as in `/search?mobile`. | ```Query(`mobile`)``` |
|
||||
| Match requests with a `mobile` query parameter set to either `true` or `yes`. | ```QueryRegexp(`mobile`, `^(true\|yes)$`)``` |
|
||||
| Match requests with a `mobile` query parameter set to any value (including the empty value). | ```QueryRegexp(`mobile`, `^.*$`)``` |
|
||||
| Match query parameters [case-insensitively](https://en.wikipedia.org/wiki/Case_sensitivity). | ```QueryRegexp(`mobile`, `(?i)^(true\|yes)$`)``` |
|
||||
|
||||
### ClientIP
|
||||
|
||||
The `ClientIP` matcher allows matching requests sent from the given client IP.
|
||||
|
||||
It only matches the request client IP and does not use the `X-Forwarded-For` header for matching.
|
||||
|
||||
| Behavior | Rule |
|
||||
|-----------------------------------------------------------------|:------------------------------------------------------------------------|
|
||||
| Match requests coming from a given IP (IPv4). | ```ClientIP(`10.76.105.11`)``` |
|
||||
| Match requests coming from a given IP (IPv6). | ```ClientIP(`::1`)``` |
|
||||
| Match requests coming from a given subnet (IPv4). | ```ClientIP(`192.168.1.0/24`)``` |
|
||||
| Match requests coming from a given subnet (IPv6). | ```ClientIP(`fe80::/10`)``` |
|
||||
|
||||
### RuleSyntax
|
||||
|
||||
In Traefik v3 a new rule syntax has been introduced ([migration guide](../../../../migration/v3.md)). the `ruleSyntax` option allows to configure the rule syntax to be used for parsing the rule on a per-router basis. This allows to have heterogeneous router configurations and ease migration.
|
||||
|
||||
The default value of the `ruleSyntax` option is inherited from the `defaultRuleSyntax` option in the install configuration (formerly known as static configuration). By default, the `defaultRuleSyntax` static option is v3, meaning that the default rule syntax is also v3
|
||||
|
||||
#### Configuration Example
|
||||
|
||||
The configuration below uses the [File Provider (Structured)](../../../install-configuration/providers/others/file.md) to configure the `ruleSyntax` to allow `Router-v2` to use v2 syntax, while for `Router-v3` it is configured to use v3 syntax.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
routers:
|
||||
Router-v3:
|
||||
rule: HostRegexp(`[a-z]+\\.traefik\\.com`)
|
||||
ruleSyntax: v3
|
||||
Router-v2:
|
||||
rule: HostRegexp(`{subdomain:[a-z]+}.traefik.com`)
|
||||
ruleSyntax: v2
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.Router-v3]
|
||||
rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
ruleSyntax = v3
|
||||
[http.routers.Router-v2]
|
||||
rule = "HostRegexp(`{subdomain:[a-z]+}.traefik.com`)"
|
||||
ruleSyntax = v2
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
- "traefik.http.routers.Router-v3.ruleSyntax=v3"
|
||||
- "traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)"
|
||||
- "traefik.http.routers.Router-v2.ruleSyntax=v2"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
|
||||
"traefik.http.routers.Router-v3.ruleSyntax=v3"
|
||||
"traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)",
|
||||
"traefik.http.routers.Router-v2.ruleSyntax=v2"
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
## Priority Calculation
|
||||
|
||||
??? info "How default priorities are computed"
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
http:
|
||||
routers:
|
||||
Router-1:
|
||||
rule: "HostRegexp(`[a-z]+\.traefik\.com`)"
|
||||
# ...
|
||||
Router-2:
|
||||
rule: "Host(`foobar.traefik.com`)"
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[http.routers]
|
||||
[http.routers.Router-1]
|
||||
rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
# ...
|
||||
[http.routers.Router-2]
|
||||
rule = "Host(`foobar.traefik.com`)"
|
||||
# ...
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
- "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
|
||||
"traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In this case, all requests with host `foobar.traefik.com` will be routed through `Router-1` instead of `Router-2`.
|
||||
|
||||
| Name | Rule | Priority |
|
||||
|----------|------------------------------------------|----------|
|
||||
| Router-1 | ```HostRegexp(`[a-z]+\.traefik\.com`)``` | 34 |
|
||||
| Router-2 | ```Host(`foobar.traefik.com`)``` | 26 |
|
||||
|
||||
The previous table shows that `Router-1` has a higher priority than `Router-2`.
|
||||
|
||||
To solve this issue, the priority must be set.
|
||||
|
||||
To avoid path overlap, routes are sorted, by default, in descending order using rules length.
|
||||
The priority is directly equal to the length of the rule, and so the longest length has the highest priority.
|
||||
|
||||
A value of `0` for the priority is ignored: `priority: 0` means that the default rules length sorting is used.
|
||||
|
||||
Traefik reserves a range of priorities for its internal routers, the maximum user-defined router priority value is:
|
||||
|
||||
- `(MaxInt32 - 1000)` for 32-bit platforms,
|
||||
- `(MaxInt64 - 1000)` for 64-bit platforms.
|
||||
|
||||
### Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
routers:
|
||||
Router-1:
|
||||
rule: "HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: service-1
|
||||
priority: 1
|
||||
Router-2:
|
||||
rule: "Host(`foobar.traefik.com`)"
|
||||
entryPoints:
|
||||
- "web"
|
||||
priority: 2
|
||||
service: service-2
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.Router-1]
|
||||
rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
entryPoints = ["web"]
|
||||
service = "service-1"
|
||||
priority = 1
|
||||
[http.routers.Router-2]
|
||||
rule = "Host(`foobar.traefik.com`)"
|
||||
entryPoints = ["web"]
|
||||
priority = 2
|
||||
service = "service-2"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)"
|
||||
- "traefik.http.routers.Router-1.entryPoints=web"
|
||||
- "traefik.http.routers.Router-1.service=service-1"
|
||||
- "traefik.http.routers.Router-1.priority=1"
|
||||
- "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)"
|
||||
- "traefik.http.routers.Router-2.entryPoints=web"
|
||||
- "traefik.http.routers.Router-2.service=service-2"
|
||||
- "traefik.http.routers.Router-2.priority=2"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)",
|
||||
"traefik.http.routers.Router-1.entryPoints=web",
|
||||
"traefik.http.routers.Router-1.service=service-1",
|
||||
"traefik.http.routers.Router-1.priority=1"
|
||||
"traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)",
|
||||
"traefik.http.routers.Router-2.entryPoints=web",
|
||||
"traefik.http.routers.Router-2.service=service-2",
|
||||
"traefik.http.routers.Router-2.priority=2"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, the priority is configured to allow `Router-2` to handle requests with the `foobar.traefik.com` host.
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: "Traefik TLS Documentation"
|
||||
description: "Learn how to configure the transport layer security (TLS) connection in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
Traefik's TLS configuration defines how TLS negotiation is handled for incoming connections.
|
||||
|
||||
The next section of this documentation explains how to configure TLS connections through a definition in the dynamic configuration and how to configure TLS options, and certificates stores.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,158 @@
|
||||
---
|
||||
title: "Traefik TLS Certificates Documentation"
|
||||
description: "Learn how to configure the transport layer security (TLS) connection in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
!!! info
|
||||
When a router has to handle HTTPS traffic, it should be specified with a `tls` field of the router definition.
|
||||
|
||||
## Certificates Definition
|
||||
|
||||
### Automated
|
||||
|
||||
See the [Let's Encrypt](../../../install-configuration/tls/certificate-resolvers/acme.md) page.
|
||||
|
||||
### User defined
|
||||
|
||||
To add / remove TLS certificates, even when Traefik is already running, their definition can be added to the [dynamic configuration](../../dynamic-configuration-methods.md#providing-dynamic-routing-configuration-to-traefik), in the `[[tls.certificates]]` section:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /path/to/domain.cert
|
||||
keyFile: /path/to/domain.key
|
||||
- certFile: /path/to/other-domain.cert
|
||||
keyFile: /path/to/other-domain.key
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/other-domain.cert"
|
||||
keyFile = "/path/to/other-domain.key"
|
||||
```
|
||||
|
||||
!!! important "Restriction"
|
||||
|
||||
In the above example, we've used the [file provider](../../../install-configuration/providers/others/file.md) to handle these definitions.
|
||||
It is the only available method to configure the certificates (as well as the options and the stores).
|
||||
However, in [Kubernetes](../../../install-configuration/providers/kubernetes/kubernetes-crd.md), the certificates can and must be provided by [secrets](https://kubernetes.io/docs/concepts/configuration/secret/).
|
||||
|
||||
## Certificates Stores
|
||||
|
||||
In Traefik, certificates are grouped together in certificates stores.
|
||||
|
||||
!!! important "Restriction"
|
||||
|
||||
Any store definition other than the default one (named `default`) will be ignored,
|
||||
and there is therefore only one globally available TLS store.
|
||||
|
||||
In the `tls.certificates` section, a list of stores can then be specified to indicate where the certificates should be stored:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /path/to/domain.cert
|
||||
keyFile: /path/to/domain.key
|
||||
stores:
|
||||
- default
|
||||
# Note that since no store is defined,
|
||||
# the certificate below will be stored in the `default` store.
|
||||
- certFile: /path/to/other-domain.cert
|
||||
keyFile: /path/to/other-domain.key
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
stores = ["default"]
|
||||
|
||||
[[tls.certificates]]
|
||||
# Note that since no store is defined,
|
||||
# the certificate below will be stored in the `default` store.
|
||||
certFile = "/path/to/other-domain.cert"
|
||||
keyFile = "/path/to/other-domain.key"
|
||||
```
|
||||
|
||||
!!! important "Restriction"
|
||||
|
||||
The `stores` list will actually be ignored and automatically set to `["default"]`.
|
||||
|
||||
### Default Certificate
|
||||
|
||||
Traefik can use a default certificate for connections without a SNI, or without a matching domain.
|
||||
This default certificate should be defined in a TLS store:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: path/to/cert.crt
|
||||
keyFile: path/to/cert.key
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tls.stores]
|
||||
[tls.stores.default]
|
||||
[tls.stores.default.defaultCertificate]
|
||||
certFile = "path/to/cert.crt"
|
||||
keyFile = "path/to/cert.key"
|
||||
```
|
||||
|
||||
If no `defaultCertificate` is provided, Traefik will use the generated one.
|
||||
|
||||
### ACME Default Certificate
|
||||
|
||||
You can configure Traefik to use an ACME provider (like Let's Encrypt) to generate the default certificate.
|
||||
The configuration to resolve the default certificate should be defined in a TLS store:
|
||||
|
||||
!!! important "Precedence with the `defaultGeneratedCert` option"
|
||||
|
||||
The `defaultGeneratedCert` definition takes precedence over the ACME default certificate configuration.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultGeneratedCert:
|
||||
resolver: myresolver
|
||||
domain:
|
||||
main: example.org
|
||||
sans:
|
||||
- foo.example.org
|
||||
- bar.example.org
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tls.stores]
|
||||
[tls.stores.default.defaultGeneratedCert]
|
||||
resolver = "myresolver"
|
||||
[tls.stores.default.defaultGeneratedCert.domain]
|
||||
main = "example.org"
|
||||
sans = ["foo.example.org", "bar.example.org"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.tls.stores.default.defaultgeneratedcert.resolver=myresolver"
|
||||
- "traefik.tls.stores.default.defaultgeneratedcert.domain.main=example.org"
|
||||
- "traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
"Name": "default",
|
||||
"Tags": [
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.resolver=myresolver",
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.domain.main=example.org",
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,228 @@
|
||||
---
|
||||
title: "Traefik TLS Options Documentation"
|
||||
description: "Learn how to configure the transport layer security (TLS) connection in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
The TLS options allow one to configure some parameters of the TLS connection.
|
||||
|
||||
!!! important "'default' TLS Option"
|
||||
|
||||
The `default` option is special.
|
||||
When no tls options are specified in a tls router, the `default` option is used.
|
||||
When specifying the `default` option explicitly, make sure not to specify provider namespace as the `default` option does not have one.
|
||||
Conversely, for cross-provider references, for example, when referencing the file provider from a docker label,
|
||||
you must specify the provider namespace, for example:
|
||||
`traefik.http.routers.myrouter.tls.options=myoptions@file`
|
||||
|
||||
!!! important "Providers"
|
||||
|
||||
TLS options are not supported by label or tag-based providers. However, you can define them when using a [KV provider](../../other-providers/kv.md).
|
||||
|
||||
### Minimum TLS Version
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
minVersion: VersionTLS12
|
||||
|
||||
mintls13:
|
||||
minVersion: VersionTLS13
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
|
||||
[tls.options.default]
|
||||
minVersion = "VersionTLS12"
|
||||
|
||||
[tls.options.mintls13]
|
||||
minVersion = "VersionTLS13"
|
||||
```
|
||||
|
||||
### Maximum TLS Version
|
||||
|
||||
We discourage the use of this setting to disable TLS1.3.
|
||||
|
||||
The recommended approach is to update the clients to support TLS1.3.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
maxVersion: VersionTLS13
|
||||
|
||||
maxtls12:
|
||||
maxVersion: VersionTLS12
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
|
||||
[tls.options.default]
|
||||
maxVersion = "VersionTLS13"
|
||||
|
||||
[tls.options.maxtls12]
|
||||
maxVersion = "VersionTLS12"
|
||||
```
|
||||
|
||||
### Cipher Suites
|
||||
|
||||
See [cipherSuites](https://godoc.org/crypto/tls#pkg-constants) for more information.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
```
|
||||
|
||||
!!! important "TLS 1.3"
|
||||
|
||||
Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa. (<https://tools.ietf.org/html/rfc8446>)
|
||||
With TLS 1.3, the cipher suites are not configurable (all supported cipher suites are safe in this case).
|
||||
<https://golang.org/doc/go1.12#tls_1_3>
|
||||
|
||||
### Curve Preferences
|
||||
|
||||
This option allows to set the preferred elliptic curves in a specific order.
|
||||
|
||||
The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used.
|
||||
|
||||
See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
curvePreferences:
|
||||
- CurveP521
|
||||
- CurveP384
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
curvePreferences = ["CurveP521", "CurveP384"]
|
||||
```
|
||||
|
||||
### Strict SNI Checking
|
||||
|
||||
With strict SNI checking enabled, Traefik won't allow connections from clients that do not specify a server_name extension
|
||||
or don't match any of the configured certificates.
|
||||
The default certificate is irrelevant on that matter.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
sniStrict: true
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
sniStrict = true
|
||||
```
|
||||
|
||||
### ALPN Protocols
|
||||
|
||||
_Optional, Default="h2, http/1.1, acme-tls/1"_
|
||||
|
||||
This option allows to specify the list of supported application level protocols for the TLS handshake,
|
||||
in order of preference.
|
||||
If the client supports ALPN, the selected protocol will be one from this list,
|
||||
and the connection will fail if there is no mutually supported protocol.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
alpnProtocols:
|
||||
- http/1.1
|
||||
- h2
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
alpnProtocols = ["http/1.1", "h2"]
|
||||
```
|
||||
|
||||
### Client Authentication (mTLS)
|
||||
|
||||
Traefik supports mutual authentication, through the `clientAuth` section.
|
||||
|
||||
For authentication policies that require verification of the client certificate, the certificate authority for the certificates should be set in `clientAuth.caFiles`.
|
||||
|
||||
In Kubernetes environment, CA certificate can be set in `clientAuth.secretNames`. See [TLSOption resource](../../kubernetes/crd/http/tlsoption.md) for more details.
|
||||
|
||||
The `clientAuth.clientAuthType` option governs the behaviour as follows:
|
||||
|
||||
| Option | Operation |
|
||||
| --------- | ----------- |
|
||||
| `NoClientCert` | Disregards any client certificate.|
|
||||
| `RequestClientCert` | Asks for a certificate but proceeds anyway if none is provided. |
|
||||
| `RequireAnyClientCert` | Requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. |
|
||||
| `VerifyClientCertIfGiven` | If a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. Otherwise proceeds without any certificate. |
|
||||
| `RequireAndVerifyClientCert` | requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. |
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Dynamic configuration
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
clientAuth:
|
||||
# in PEM format. each file can contain multiple CAs.
|
||||
caFiles:
|
||||
- tests/clientca1.crt
|
||||
- tests/clientca2.crt
|
||||
clientAuthType: RequireAndVerifyClientCert
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Dynamic configuration
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
[tls.options.default.clientAuth]
|
||||
# in PEM format. each file can contain multiple CAs.
|
||||
caFiles = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||
clientAuthType = "RequireAndVerifyClientCert"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,561 @@
|
||||
---
|
||||
title: "Kubernetes IngressRoute"
|
||||
description: "An IngressRoute is a Traefik CRD is in charge of connecting incoming requests to the Services that can handle them in HTTP."
|
||||
---
|
||||
|
||||
`IngressRoute` is the CRD implementation of a [Traefik HTTP router](../../../http/router/rules-and-priority.md).
|
||||
|
||||
Before creating `IngressRoute` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `IngressRoute` kind and other Traefik-specific resources.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
You can declare an `IngressRoute` as detailed below:
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test-name
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- kind: Rule
|
||||
# Rule on the Host
|
||||
match: Host(`test.example.com`)
|
||||
# Attach a middleware
|
||||
middlewares:
|
||||
- name: middleware1
|
||||
namespace: apps
|
||||
# Enable Router observability
|
||||
observability:
|
||||
accesslogs: true
|
||||
metrics: true
|
||||
tracing: true
|
||||
# Set a pirority
|
||||
priority: 10
|
||||
services:
|
||||
# Target a Kubernetes Support
|
||||
- kind: Service
|
||||
name: foo
|
||||
namespace: apps
|
||||
# Customize the connection between Traefik and the backend
|
||||
passHostHeader: true
|
||||
port: 80
|
||||
responseForwarding:
|
||||
flushInterval: 1ms
|
||||
scheme: https
|
||||
sticky:
|
||||
cookie:
|
||||
httpOnly: true
|
||||
name: cookie
|
||||
secure: true
|
||||
strategy: RoundRobin
|
||||
weight: 10
|
||||
tls:
|
||||
# Generate a TLS certificate using a certificate resolver
|
||||
certResolver: foo
|
||||
domains:
|
||||
- main: example.net
|
||||
sans:
|
||||
- a.example.net
|
||||
- b.example.net
|
||||
# Customize the TLS options
|
||||
options:
|
||||
name: opt
|
||||
namespace: apps
|
||||
# Add a TLS certificate from a Kubernetes Secret
|
||||
secretName: supersecret
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `entryPoints` | List of [entry points](../../../../install-configuration/entrypoints.md) names.<br />If not specified, HTTP routers will accept requests from all EntryPoints in the list of default EntryPoints. | | No |
|
||||
| `routes` | List of routes. | | Yes |
|
||||
| `routes[n].kind` | Kind of router matching, only `Rule` is allowed yet. | "Rule" | No |
|
||||
| `routes[n].match` | Defines the [rule](../../../http/router/rules-and-priority.md#rules) corresponding to an underlying router. | | Yes |
|
||||
| `routes[n].priority` | Defines the [priority](../../../http/router/rules-and-priority.md#priority-calculation) to disambiguate rules of the same length, for route matching.<br />If not set, the priority is directly equal to the length of the rule, and so the longest length has the highest priority.<br />A value of `0` for the priority is ignored, the default rules length sorting is used. | 0 | No |
|
||||
| `routes[n].middlewares` | List of middlewares to attach to the IngressRoute. <br />More information [here](#middleware). | "" | No |
|
||||
| `routes[n].`<br />`middlewares[m].`<br />`name` | Middleware name.<br />The character `@` is not authorized. <br />More information [here](#middleware). | | Yes |
|
||||
| `routes[n].`<br />`middlewares[m].`<br />`namespace` | Middleware namespace.<br />Can be empty if the middleware belongs to the same namespace as the IngressRoute. <br />More information [here](#middleware). | | No |
|
||||
| `routes[n].`<br />`observability.`<br />`accesslogs` | Defines whether the route will produce [access-logs](../../../../install-configuration/observability/logs-and-accesslogs.md). See [here](../../../http/router/observability.md) for more information. | false | No |
|
||||
| `routes[n].`<br />`observability.`<br />`metrics` | Defines whether the route will produce [metrics](../../../../install-configuration/observability/metrics.md). See [here](../../../http/router/observability.md) for more information. | false | No |
|
||||
| `routes[n].`<br />`observability.`<br />`tracing` | Defines whether the route will produce [traces](../../../../install-configuration/observability/tracing.md). See [here](../../../http/router/observability.md) for more information. | false | No |
|
||||
| `routes[n].`<br />`services` | List of any combination of TraefikService and [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). <br />More information [here](#externalname-service). | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`kind` | Kind of the service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br /> **TraefikService**: Traefik Service.<br />More information [here](#externalname-service). | "Service" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`name` | Service name.<br />The character `@` is not authorized. <br />More information [here](#middleware). | | Yes |
|
||||
| `routes[n].`<br />`services[m].`<br />`namespace` | Service namespace.<br />Can be empty if the service belongs to the same namespace as the IngressRoute. <br />More information [here](#externalname-service). | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`port` | Service port (number or port name).<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`responseForwarding.`<br />`flushInterval` | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind is **Service**. | 100ms | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`scheme` | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`serversTransport` | Name of ServersTransport resource to use to configure the transport between Traefik and your servers.<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`passHostHeader` | Forward client Host header to server.<br />Evaluated only if the kind is **Service**. | true | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.scheme` | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.mode` | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "http" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.path` | Server URL path for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.interval` | Frequency of the health check calls.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "100ms" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.method` | HTTP method for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "GET" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.status` | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.port` | URL port for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.timeout` | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "5s" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.hostname` | Value in the Host header of the health check request.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.`<br />`followRedirect` | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service). | true | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`healthCheck.headers` | Map of header to send to the health check endpoint<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#externalname-service)). | | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`sticky.`<br />`cookie.name` | Name of the cookie used for the stickiness.<br />When sticky sessions are enabled, a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response.<br />On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set.<br />If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`sticky.`<br />`cookie.httpOnly` | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`sticky.`<br />`cookie.secure` | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`sticky.`<br />`cookie.sameSite` | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`sticky.`<br />`cookie.maxAge` | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind is **Service**. | 0 | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`strategy` | Load balancing strategy between the servers.<br />RoundRobin is the only supported value yet.<br />Evaluated only if the kind is **Service**. | "RoundRobin" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`weight` | Service weight.<br />To use only to refer to WRR TraefikService | "" | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`nativeLB` | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br /> Evaluated only if the kind is **Service**. | false | No |
|
||||
| `routes[n].`<br />`services[m].`<br />`nodePortLB` | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `tls` | TLS configuration.<br />Can be an empty value(`{}`):<br />A self signed is generated in such a case<br />(or the [default certificate](tlsstore.md) is used if it is defined.) | | No |
|
||||
| `tls.secretName` | [Secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the same namesapce as the `IngressRoute`) | "" | No |
|
||||
| `tls.`<br />`options.name` | Name of the [`TLSOption`](tlsoption.md) to use.<br />More information [here](#tls-options). | "" | No |
|
||||
| `tls.`<br />`options.namespace` | Namespace of the [`TLSOption`](tlsoption.md) to use. | "" | No |
|
||||
| `tls.certResolver` | Name of the [Certificate Resolver](../../../../install-configuration/tls/certificate-resolvers/overview.md) to use to generate automatic TLS certificates. | "" | No |
|
||||
| `tls.domains` | List of domains to serve using the certificates generates (one `tls.domain`= one certificate).<br />More information in the [dedicated section](../../../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition). | | No |
|
||||
| `tls.`<br />`domains[n].main` | Main domain name | "" | Yes |
|
||||
| `tls.`<br />`domains[n].sans` | List of alternative domains (SANs) | | No |
|
||||
|
||||
### ExternalName Service
|
||||
|
||||
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) could be defined without any port. Accordingly, Traefik supports defining a port in two ways:
|
||||
|
||||
- only on `IngressRoute` service
|
||||
- on both sides, you'll be warned if the ports don't match, and the `IngressRoute` service port is used
|
||||
|
||||
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||
|
||||
=== "Ports defined on Resource"
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
```
|
||||
|
||||
=== "Port defined on the Service"
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
=== "Port defined on both sides"
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
- You can attach a list of [middlewares](../../../http/middlewares/overview.md)
|
||||
to each HTTP router.
|
||||
- The middlewares will take effect only if the rule matches, and before forwarding
|
||||
the request to the service.
|
||||
- Middlewares are applied in the same order as their declaration in **router**.
|
||||
- In Kubernetes, the option `middleware` allow you to attach a middleware using its
|
||||
name and namespace (the namespace can be omitted when the Middleware is in the
|
||||
same namespace as the IngressRoute)
|
||||
|
||||
??? example "IngressRoute attached to a few middlewares"
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: my-app
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`example.com`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
# same namespace as the IngressRoute
|
||||
- name: middleware01
|
||||
# default namespace
|
||||
- name: middleware02
|
||||
namespace: apps
|
||||
# Other namespace
|
||||
- name: middleware03
|
||||
namespace: other-ns
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
??? abstract "routes.services.kind"
|
||||
|
||||
As the field `name` can reference different types of objects, use the field `kind` to avoid any ambiguity.
|
||||
The field `kind` allows the following values:
|
||||
|
||||
- `Service` (default value): to reference a [Kubernetes Service](https://kubernetes.io/docs/concepts/services-networking/service/)
|
||||
- `TraefikService`: to reference an object [`TraefikService`](../http/traefikservice.md)
|
||||
|
||||
### Port Definition
|
||||
|
||||
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) could be defined without any port. Accordingly, Traefik supports defining a port in two ways:
|
||||
|
||||
- only on `IngressRoute` service
|
||||
- on both sides, you'll be warned if the ports don't match, and the `IngressRoute` service port is used
|
||||
|
||||
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||
|
||||
??? example
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
```
|
||||
|
||||
```yaml tab="ExternalName Service"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Both sides"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: default
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
### TLS Options
|
||||
|
||||
The `options` field enables fine-grained control of the TLS parameters.
|
||||
It refers to a [TLSOption](./tlsoption.md) and will be applied only if a `Host`
|
||||
rule is defined.
|
||||
|
||||
#### Server Name Association
|
||||
|
||||
A TLS options reference is always mapped to the host name found in the `Host`
|
||||
part of the rule, but neither to a router nor a router rule.
|
||||
There could also be several `Host` parts in a rule.
|
||||
In such a case the TLS options reference would be mapped to as many host names.
|
||||
|
||||
A TLS option is picked from the mapping mentioned above and based on the server
|
||||
name provided during the TLS handshake,
|
||||
and it all happens before routing actually occurs.
|
||||
|
||||
In the case of domain fronting,
|
||||
if the TLS options associated with the Host Header and the SNI are different then
|
||||
Traefik will respond with a status code `421`.
|
||||
|
||||
#### Conflicting TLS Options
|
||||
|
||||
Since a TLS options reference is mapped to a host name, if a configuration introduces
|
||||
a situation where the same host name (from a `Host` rule) gets matched with two
|
||||
TLS options references, a conflict occurs, such as in the example below.
|
||||
|
||||
??? example
|
||||
|
||||
```yaml tab="IngressRoute01"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: IngressRoute01
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
tls:
|
||||
options: foo
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="IngressRoute02"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: IngressRoute02
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
tls:
|
||||
options: bar
|
||||
...
|
||||
```
|
||||
|
||||
If that happens, both mappings are discarded, and the host name
|
||||
(`example.net` in the example) for these routers gets associated with
|
||||
the default TLS options instead.
|
||||
|
||||
### Load Balancing
|
||||
|
||||
You can declare and use Kubernetes Service load balancing as detailed below:
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: svc1
|
||||
namespace: default
|
||||
- name: svc2
|
||||
namespace: default
|
||||
```
|
||||
|
||||
```yaml tab="K8s Service"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc2
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app2
|
||||
```
|
||||
|
||||
!!! important "Kubernetes Service Native Load-Balancing"
|
||||
|
||||
To avoid creating the server load-balancer with the pod IPs and use Kubernetes Service clusterIP directly,
|
||||
one should set the service `NativeLB` option to true.
|
||||
Please note that, by default, Traefik reuses the established connections to the backends for performance purposes. This can prevent the requests load balancing between the replicas from behaving as one would expect when the option is set.
|
||||
By default, `NativeLB` is false.
|
||||
|
||||
??? example "Example"
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: svc
|
||||
port: 80
|
||||
# Here, nativeLB instructs to build the server load-balancer with the Kubernetes Service clusterIP only.
|
||||
nativeLB: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc
|
||||
namespace: default
|
||||
spec:
|
||||
type: ClusterIP
|
||||
...
|
||||
```
|
||||
|
||||
### Configuring Backend Protocol
|
||||
|
||||
There are 3 ways to configure the backend protocol for communication between Traefik and your pods:
|
||||
|
||||
- Setting the scheme explicitly (http/https/h2c)
|
||||
- Configuring the name of the kubernetes service port to start with https (https)
|
||||
- Setting the kubernetes service port to use port 443 (https)
|
||||
|
||||
If you do not configure the above, Traefik will assume an http connection.
|
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Traefik Kubernetes Middleware Documentation"
|
||||
description: "Learn how to configure a Traefik Proxy Kubernetes Middleware to reach Services, which handle incoming requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
`Middleware` is the CRD implementation of a [Traefik middleware](../../../http/middlewares/overview.md).
|
||||
|
||||
Before creating `Middleware` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `Middleware` kind and other Traefik-specific resources.
|
||||
|
||||
!!! tip "Cross-provider namespace"
|
||||
As Kubernetes also has its own notion of namespace, one should not confuse the Kubernetes namespace of a resource (in the reference to the middleware) with the [provider namespace](../../../../install-configuration/providers/overview.md#provider-namespace), when the definition of the middleware comes from another provider. In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored. Additionally, when you want to reference a Middleware from the CRD Provider, you have to append the namespace of the resource in the resource-name as Traefik appends the namespace internally automatically.
|
||||
|
||||
!!! note "Cross-Namespace References"
|
||||
In the example below, the middleware is defined in the `foo` namespace while being referenced from an IngressRoute in another namespace. To enable such cross-namespace references, the `allowCrossNamespace` option must be enabled in the Traefik [Kubernetes CRD provider](../../../../install-configuration/providers/kubernetes/kubernetes-crd.md#configuration-options) configuration. If you prefer to avoid this requirement, you can define and reference the Middleware within the same namespace.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Middleware"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: stripprefix
|
||||
namespace: foo
|
||||
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /stripit
|
||||
```
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/stripit`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
namespace: foo
|
||||
```
|
||||
|
||||
For more information about the available middlewares, navigate to the dedicated [middlewares overview section](../../../http/middlewares/overview.md).
|
@ -0,0 +1,72 @@
|
||||
---
|
||||
title: "Kubernetes serversTransport"
|
||||
description: "The Kubernetes ServersTransport allows configuring the connection between Traefik and the HTTP servers in Kubernetes."
|
||||
---
|
||||
|
||||
A `ServersTransport` allows you to configure the connection between Traefik and the HTTP servers in Kubernetes.
|
||||
|
||||
Before creating `ServersTransport` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `ServersTransport` kind and other Traefik-specific resources.
|
||||
|
||||
It can be applied on a service using:
|
||||
|
||||
- The option `services.serverstransport` on a [`IngressRoute`](./ingressroute.md) (if the service is a Kubernetes Service)
|
||||
- The option `serverstransport` on a [`TraefikService`](./traefikservice.md) (if the service is a Kubernetes Service)
|
||||
|
||||
!!! note "Reference a ServersTransport CRD from another namespace"
|
||||
|
||||
The value must be of form `namespace-name@kubernetescrd`, and the `allowCrossNamespace` option must be enabled at the provider level.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="serversTransport"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: ServersTransport
|
||||
metadata:
|
||||
name: mytransport
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
serverName: example.org
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: testroute
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
serversTransport: mytransport
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `serverstransport.`<br />`serverName` | Defines the server name that will be used for SNI. | | No |
|
||||
| `serverstransport.`<br />`insecureSkipVerify` | Controls whether the server's certificate chain and host name is verified. | false | No |
|
||||
| `serverstransport.`<br />`rootcas` | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
|
||||
| `serverstransport.`<br />`certificatesSecrets` | Certificates to present to the server for mTLS. | | No |
|
||||
| `serverstransport.`<br />`maxIdleConnsPerHost` | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
|
||||
| `serverstransport.`<br />`disableHTTP2` | Disables HTTP/2 for connections with servers. | false | No |
|
||||
| `serverstransport.`<br />`peerCertURI` | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
|
||||
| `serverstransport.`<br />`forwardingTimeouts.dialTimeout` | Amount of time to wait until a connection to a server can be established.<br />Zero means no timeout. | 30s | No |
|
||||
| `serverstransport.`<br />`forwardingTimeouts.responseHeaderTimeout` | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />Zero means no timeout | 0s | No |
|
||||
| `serverstransport.`<br />`forwardingTimeouts.idleConnTimeout` | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />Zero means no timeout. | 90s | No |
|
||||
| `serverstransport.`<br />`spiffe.ids` | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
|
||||
| `serverstransport.`<br />`spiffe.trustDomain` | Allow SPIFFE trust domain. | "" | No |
|
||||
|
||||
!!! note "CA Secret"
|
||||
The CA secret must contain a base64 encoded certificate under either a tls.ca or a ca.crt key.
|
@ -0,0 +1,82 @@
|
||||
---
|
||||
title: "TLSOption"
|
||||
description: "TLS Options in Traefik Proxy"
|
||||
---
|
||||
|
||||
The TLS options allow you to configure some parameters of the TLS connection in Traefik.
|
||||
|
||||
Before creating `TLSOption` objects or referencing TLS options in the [`IngressRoute`](../http/ingressroute.md) / [`IngressRouteTCP`](../tcp/ingressroutetcp.md) objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
!!! tip "References and namespaces"
|
||||
If the optional namespace attribute is not set, the configuration will be applied with the namespace of the `IngressRoute`/`IngressRouteTCP`.
|
||||
|
||||
Additionally, when the definition of the TLS option is from another provider, the cross-provider [syntax](../../../../install-configuration/providers/overview.md#provider-namespace) (`middlewarename@provider`) should be used to refer to the TLS option. Specifying a namespace attribute in this case would not make any sense, and will be ignored.
|
||||
|
||||
!!! important "TLSOption in Kubernetes"
|
||||
|
||||
When using the `TLSOption` resource in Kubernetes, one might setup a default set of options that,
|
||||
if not explicitly overwritten, should apply to all ingresses.
|
||||
To achieve that, you'll have to create a `TLSOption` resource with the name `default`.
|
||||
There may exist only one `TLSOption` with the name `default` (across all namespaces) - otherwise they will be dropped.
|
||||
To explicitly use a different `TLSOption` (and using the Kubernetes Ingress resources)
|
||||
you'll have to add an annotation to the Ingress in the following form:
|
||||
`traefik.ingress.kubernetes.io/router.tls.options: <resource-namespace>-<resource-name>@kubernetescrd`
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="TLSOption"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minVersion: VersionTLS12
|
||||
sniStrict: true
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientAuth:
|
||||
secretNames:
|
||||
- secret-ca1
|
||||
- secret-ca2
|
||||
clientAuthType: VerifyClientCertIfGiven
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------|:---------|
|
||||
| `minVersion` | Minimum TLS version that is acceptable. | "VersionTLS12" | No |
|
||||
| `maxVersion` | Maximum TLS version that is acceptable.<br />We do not recommend setting this option to disable TLS 1.3. | | No |
|
||||
| `cipherSuites` | List of supported [cipher suites](https://godoc.org/crypto/tls#pkg-constants) for TLS versions up to TLS 1.2.<br />[Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa.](https://tools.ietf.org/html/rfc8446)<br />With TLS 1.3, [the cipher suites are not configurable](https://golang.org/doc/go1.12#tls_1_3) (all supported cipher suites are safe in this case). | | No |
|
||||
| `curvePreferences` | List of the elliptic curves references that will be used in an ECDHE handshake, in preference order.<br />Use curves names from [`crypto`](https://godoc.org/crypto/tls#CurveID) or the [RFC](https://tools.ietf.org/html/rfc8446#section-4.2.7).<br />See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information. | | No |
|
||||
| `clientAuth.secretNames` | Client Authentication (mTLS) option.<br />List of names of the referenced Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) (in TLSOption namespace).<br /> The secret must contain a certificate under either a `tls.ca` or a `ca.crt` key. | | No |
|
||||
| `clientAuth.clientAuthType` | Client Authentication (mTLS) option.<br />Client authentication type to apply. Available values [here](#client-authentication-mtls). | | No |
|
||||
| `sniStrict` | Allow rejecting connections from clients connections that do not specify a server_name extension.<br />The [default certificate](../../../http/tls/tls-certificates.md#default-certificate) is never served is the option is enabled. | false | No |
|
||||
| `alpnProtocols` | List of supported application level protocols for the TLS handshake, in order of preference.<br />If the client supports ALPN, the selected protocol will be one from this list, and the connection will fail if there is no mutually supported protocol. | "h2, http/1.1, acme-tls/1" | No |
|
||||
|
||||
### Client Authentication (mTLS)
|
||||
|
||||
The `clientAuth.clientAuthType` option governs the behaviour as follows:
|
||||
|
||||
- `NoClientCert`: disregards any client certificate.
|
||||
- `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided.
|
||||
- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`.
|
||||
- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. Otherwise proceeds without any certificate.
|
||||
- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`.
|
||||
|
||||
!!! note "CA Secret"
|
||||
The CA secret must contain a base64 encoded certificate under either a `tls.ca` or a `ca.crt` key.
|
||||
|
||||
### Default TLS Option
|
||||
|
||||
When no TLS options are specified in an `IngressRoute`/`IngressRouteTCP`, the `default` option is used.
|
||||
The default behavior is summed up in the table below:
|
||||
|
||||
| Configuration | Behavior |
|
||||
|:--------------------------|:-----------------------------------------------------------|
|
||||
| No `default` TLS Option | Default internal set of TLS Options by default. |
|
||||
| One `default` TLS Option | Custom TLS Options applied by default. |
|
||||
| Many `default` TLS Option | Error log + Default internal set of TLS Options by default. |
|
@ -0,0 +1,39 @@
|
||||
---
|
||||
title: "TLSStore"
|
||||
description: "TLS Store in Traefik Proxy"
|
||||
---
|
||||
|
||||
In Traefik, certificates are grouped together in certificates stores.
|
||||
|
||||
`TLSStore` is the CRD implementation of a [Traefik TLS Store](../../../http/tls/tls-certificates.md#certificates-stores).
|
||||
|
||||
Before creating `TLSStore` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
!!! Tip "Default TLS Store"
|
||||
Traefik currently only uses the TLS Store named "default". This default `TLSStore` should be in a namespace discoverable by Traefik. Since it is used by default on `IngressRoute` and `IngressRouteTCP` objects, there never is a need to actually reference it. This means that you cannot have two stores that are named default in different Kubernetes namespaces. As a consequence, with respect to TLS stores, the only change that makes sense (and only if needed) is to configure the default `TLSStore`.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="TLSStore"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TLSStore
|
||||
metadata:
|
||||
name: default
|
||||
|
||||
spec:
|
||||
defaultCertificate:
|
||||
secretName: supersecret
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Required |
|
||||
|:---------------------------------------|:-------------------------|:---------|
|
||||
| `certificates[n].secretName` | List of Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/), each of them holding a key/certificate pair to add to the store. | No |
|
||||
| `defaultCertificate.secretName` | Name of the Kubernetes [Secret](https://kubernetes.io/docs/concepts/configuration/secret/) served for connections without a SNI, or without a matching domain. If no default certificate is provided, Traefik will use the generated one. Do not use if the option `defaultGeneratedCert` is set. | No |
|
||||
| `defaultGeneratedCert.resolver` | Name of the ACME resolver to use to generate the default certificate.<br /> Do not use if the option `defaultCertificate` is set. | No |
|
||||
| `defaultGeneratedCert.domain.main` | Main domain used to generate the default certificate.<br /> Do not use if the option `defaultCertificate` is set. | No |
|
||||
| `defaultGeneratedCert.domain.sans` | List of [Subject Alternative Name](https://en.wikipedia.org/wiki/Subject_Alternative_Name) used to generate the default certificate.<br /> Do not use if the option `defaultCertificate` is set. | No |
|
||||
|
||||
!!! note "DefaultCertificate vs DefaultGeneratedCert"
|
||||
If both `defaultCertificate` and `defaultGeneratedCert` are set, the TLS certificate contained in `defaultCertificate.secretName` is served. The ACME default certificate is not generated.
|
@ -0,0 +1,436 @@
|
||||
---
|
||||
title: "Traefik Kubernetes Services Documentation"
|
||||
description: "Learn how to configure routing and load balancing in Traefik Proxy to reach Services, which handle incoming requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
A `TraefikService` is a custom resource that sits on top of the Kubernetes Services. It enables advanced load-balancing features such as a [Weighted Round Robin](#weighted-round-robin) load balancing or a [Mirroring](#mirroring) between your Kubernetes Services.
|
||||
|
||||
Services configure how to reach the actual endpoints that will eventually handle incoming requests. In Traefik, the target service can be either a standard [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/)—which exposes a pod—or a TraefikService. The latter allows you to combine advanced load-balancing options like:
|
||||
|
||||
- [Weighted Round Robin load balancing](#weighted-round-robin).
|
||||
- [Mirroring](#mirroring).
|
||||
|
||||
## Weighted Round Robin
|
||||
|
||||
The WRR is able to load balance the requests between multiple services based on weights. The WRR `TraefikService` allows you to load balance the traffic between Kubernetes Services and other instances of `TraefikService` (another WRR service -, or a mirroring service).
|
||||
|
||||
### Configuration Example
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test-name
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
services:
|
||||
# Set a WRR TraefikService
|
||||
- name: wrr1
|
||||
namespace: apps
|
||||
kind: TraefikService
|
||||
tls:
|
||||
# Add a TLS certificate from a Kubernetes Secret
|
||||
secretName: supersecret
|
||||
```
|
||||
|
||||
```yaml tab="TraefikService WRR Level#1"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: wrr1
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
weighted:
|
||||
services:
|
||||
# Kubernetes Service
|
||||
- name: svc1
|
||||
namespace: apps
|
||||
port: 80
|
||||
weight: 1
|
||||
# Second level WRR service
|
||||
- name: wrr2
|
||||
namespace: apps
|
||||
kind: TraefikService
|
||||
weight: 1
|
||||
# Mirroring service
|
||||
# The service is described in the Mirroring example
|
||||
- name: mirror1
|
||||
namespace: apps
|
||||
kind: TraefikService
|
||||
weight: 1
|
||||
```
|
||||
|
||||
```yaml tab="TraefikService WRR Level#2"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: wrr2
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
weighted:
|
||||
services:
|
||||
# Kubernetes Service
|
||||
- name: svc2
|
||||
namespace: apps
|
||||
port: 80
|
||||
weight: 1
|
||||
# Kubernetes Service
|
||||
- name: svc3
|
||||
namespace: apps
|
||||
port: 80
|
||||
weight: 1
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes Services"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc2
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app2
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc3
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app3
|
||||
```
|
||||
|
||||
```yaml tab="Secret"
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: apps
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `services` | List of any combination of TraefikService and [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). <br />. | | No |
|
||||
| `services[m].`<br />`kind` | Kind of the service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br /> - **TraefikService**: Traefik Service. | "" | No |
|
||||
| `services[m].`<br />`name` | Service name.<br />The character `@` is not authorized. | "" | Yes |
|
||||
| `services[m].`<br />`namespace` | Service namespace. | "" | No |
|
||||
| `services[m].`<br />`port` | Service port (number or port name).<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `services[m].`<br />`responseForwarding.`<br />`flushInterval` | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind is **Service**. | 100ms | No |
|
||||
| `services[m].`<br />`scheme` | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| `services[m].`<br />`serversTransport` | Name of ServersTransport resource to use to configure the transport between Traefik and your servers.<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `services[m].`<br />`passHostHeader` | Forward client Host header to server.<br />Evaluated only if the kind is **Service**. | true | No |
|
||||
| `services[m].`<br />`healthCheck.scheme` | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||
| `services[m].`<br />`healthCheck.mode` | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "http" | No |
|
||||
| `services[m].`<br />`healthCheck.path` | Server URL path for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||
| `services[m].`<br />`healthCheck.interval` | Frequency of the health check calls.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName]`ExternalName`. | "100ms" | No |
|
||||
| `services[m].`<br />`healthCheck.method` | HTTP method for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "GET" | No |
|
||||
| `services[m].`<br />`healthCheck.status` | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind is **Service**. | | No |
|
||||
| `services[m].`<br />`healthCheck.port` | URL port for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | | No |
|
||||
| `services[m].`<br />`healthCheck.timeout` | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "5s" | No |
|
||||
| `services[m].`<br />`healthCheck.hostname` | Value in the Host header of the health check request.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||
| `services[m].`<br />`healthCheck.`<br />`followRedirect` | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | true | No |
|
||||
| `services[m].`<br />`healthCheck.headers` | Map of header to send to the health check endpoint<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | | No |
|
||||
| `services[m].`<br />`sticky.`<br />`cookie.name` | Name of the cookie used for the stickiness.<br />Evaluated only if the kind is **Service**. | Abbreviation of a sha1<br />(ex: `_1d52e`). | No |
|
||||
| `services[m].`<br />`sticky.`<br />`cookie.httpOnly` | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `services[m].`<br />`sticky.`<br />`cookie.secure` | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `services[m].`<br />`sticky.`<br />`cookie.sameSite` | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy.<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||
| `services[m].`<br />`sticky.`<br />`cookie.maxAge` | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind is **Service**. | 0 | No |
|
||||
| `services[m].`<br />`strategy` | Load balancing strategy between the servers.<br />RoundRobin is the only supported value yet.<br />Evaluated only if the kind is **Service**. | "RoundRobin" | No |
|
||||
| `services[m].`<br />`weight` | Service weight.<br />To use only to refer to WRR TraefikService | "" | No |
|
||||
| `services[m].`<br />`nativeLB` | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `services[m].`<br />`nodePortLB` | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||
| `sticky.`<br />`cookie.name` | Name of the cookie used for the stickiness at the WRR service level.<br />When sticky sessions are enabled, a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response.<br />On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set.<br />If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).<br />More information about WRR stickiness [here](#stickiness-on-multiple-levels) | Abbreviation of a sha1<br />(ex: `_1d52e`). | No |
|
||||
| `sticky.`<br />`cookie.httpOnly` | Allow the cookie used for the stickiness at the WRR service level to be accessed by client-side APIs, such as JavaScript.<br />More information about WRR stickiness [here](#stickiness-on-multiple-levels) | false | No |
|
||||
| `sticky.`<br />`cookie.secure` | Allow the cookie used for the stickiness at the WRR service level to be only transmitted over an encrypted connection (i.e. HTTPS).<br />More information about WRR stickiness [here](#stickiness-on-multiple-levels) | false | No |
|
||||
| `sticky.`<br />`cookie.sameSite` | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy for the cookie used for the stickiness at the WRR service level.<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />More information about WRR stickiness [here](#stickiness-on-multiple-levels) | "" | No |
|
||||
| `sticky.`<br />`cookie.maxAge` | Number of seconds until the cookie used for the stickiness at the WRR service level expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires. | 0 | No |
|
||||
|
||||
#### Stickiness on multiple levels
|
||||
|
||||
When chaining or mixing load-balancers (e.g. a load-balancer of servers is one of the "children" of a load-balancer of services),
|
||||
for stickiness to work all the way, the option needs to be specified at all required levels.
|
||||
Which means the client needs to send a cookie with as many key/value pairs as there are sticky levels.
|
||||
|
||||
Sticky sessions, for stickiness to work all the way, must be specified at each load-balancing level.
|
||||
|
||||
For instance, in the example below, there is a first level of load-balancing because there is a (Weighted Round Robin) load-balancing of the two `whoami` services,
|
||||
and there is a second level because each whoami service is a `replicaset` and is thus handled as a load-balancer of servers.
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: wrr1
|
||||
namespace: apps
|
||||
kind: TraefikService
|
||||
```
|
||||
|
||||
```yaml tab="TraefikService WRR with 2 level of stickiness"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: wrr1
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
weighted:
|
||||
services:
|
||||
- name: whoami1
|
||||
kind: Service
|
||||
port: 80
|
||||
weight: 1
|
||||
# Stickiness level2 (on the Kubernetes service)
|
||||
sticky:
|
||||
cookie:
|
||||
name: lvl2
|
||||
- name: whoami2
|
||||
kind: Service
|
||||
weight: 1
|
||||
port: 80
|
||||
# Stickiness level2 (on the Kubernetes service)
|
||||
sticky:
|
||||
cookie:
|
||||
name: lvl2
|
||||
# Stickiness level2 (on the WRR service)
|
||||
sticky:
|
||||
cookie:
|
||||
name: lvl1
|
||||
```
|
||||
|
||||
In the example above, to keep a session open with the same server, the client would then need to specify the two levels within the cookie for each request, e.g. with curl:
|
||||
|
||||
```bash
|
||||
# Assuming `10.42.0.6` is the IP address of one of the replicas (a pod then) of the `whoami1` service.
|
||||
curl -H Host:example.com -b "lvl1=default-whoami1-80; lvl2=http://10.42.0.6:80" http://localhost:8000/foo
|
||||
```
|
||||
|
||||
## Mirroring
|
||||
|
||||
The mirroring is able to mirror requests sent to a service to other services.
|
||||
|
||||
A mirroring service allows you to send the trafiic to many services together:
|
||||
|
||||
- The **main** service receives 100% of the traffic,
|
||||
- The **mirror** services receive a percentage of the traffic.
|
||||
|
||||
For example, to upgrade the version of your application. You can set the service that targets current version as the **main** service, and the service of the new version a **mirror** service.
|
||||
Thus you can start testing the behavior of the new version keeping the current version reachable.
|
||||
|
||||
The mirroring `TraefikService` allows you to reference Kubernetes Services and other instances of `TraefikService` (another WRR service -, or a mirroring service).
|
||||
|
||||
Please note that by default the whole request is buffered in memory while it is being mirrored.
|
||||
See the `maxBodySize` option in the example below for how to modify this behavior.
|
||||
|
||||
### Configuration Example
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: mirror1
|
||||
namespace: default
|
||||
kind: TraefikService
|
||||
```
|
||||
|
||||
```yaml tab="Mirroring from a Kubernetes Service"
|
||||
# Mirroring from a k8s Service
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: mirror1
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
mirroring:
|
||||
name: svc1 # svc1 receives 100% of the traffic
|
||||
port: 80
|
||||
mirrors:
|
||||
- name: svc2 # svc2 receives a copy of 20% of this traffic
|
||||
port: 80
|
||||
percent: 20
|
||||
- name: svc3 # svc3 receives a copy of 15% of this traffic
|
||||
kind: TraefikService
|
||||
percent: 15
|
||||
```
|
||||
|
||||
```yaml tab="Mirroring from a TraefikService (WRR)"
|
||||
# Mirroring from a Traefik Service
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: mirror1
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
mirroring:
|
||||
name: wrr1 # wrr1 receives 100% of the traffic
|
||||
kind: TraefikService
|
||||
mirrors:
|
||||
- name: svc2 # svc2 receives a copy of 20% of this traffic
|
||||
port: 80
|
||||
percent: 20
|
||||
- name: svc3 # svc3 receives a copy of 10% of this traffic
|
||||
kind: TraefikService
|
||||
percent: 10
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes Services"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc2
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: app2
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
!!!note "Main and mirrored services"
|
||||
|
||||
The main service properties are set as the option root level.
|
||||
|
||||
The mirrored services properties are set in the `mirrors` list.
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `kind` | Kind of the main service.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br />- **TraefikService**: Traefik Service.<br />More information [here](#services) | "" | No |
|
||||
| `name` | Main service name.<br />The character `@` is not authorized. | "" | Yes |
|
||||
| `namespace` | Main service namespace.<br />More information [here](#services). | "" | No |
|
||||
| `port` | Main service port (number or port name).<br />Evaluated only if the kind of the main service is **Service**. | "" | No |
|
||||
| `responseForwarding.`<br />`flushInterval` | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind of the main service is **Service**. | 100ms | No |
|
||||
| `scheme` | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind of the main service is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| `serversTransport` | Name of ServersTransport resource to use to configure the transport between Traefik and the main service's servers.<br />Evaluated only if the kind of the main service is **Service**. | "" | No |
|
||||
| `passHostHeader` | Forward client Host header to main service's server.<br />Evaluated only if the kind of the main service is **Service**. | true | No |
|
||||
| `healthCheck.scheme` | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `healthCheck.mode` | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "http" | No |
|
||||
| `healthCheck.path` | Server URL path for the health check endpoint.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `healthCheck.interval` | Frequency of the health check calls.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "100ms" | No |
|
||||
| `healthCheck.method` | HTTP method for the health check endpoint.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "GET" | No |
|
||||
| `healthCheck.status` | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind of the main service is **Service**. | | No |
|
||||
| `healthCheck.port` | URL port for the health check endpoint.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | | No |
|
||||
| `healthCheck.timeout` | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "5s" | No |
|
||||
| `healthCheck.hostname` | Value in the Host header of the health check request.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `healthCheck.`<br />`followRedirect` | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | true | No |
|
||||
| `healthCheck.headers` | Map of header to send to the health check endpoint<br />Evaluated only if the kind of the main service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | | No |
|
||||
| `sticky.`<br />`cookie.name` | Name of the cookie used for the stickiness on the main service.<br />Evaluated only if the kind of the main service is **Service**. | Abbreviation of a sha1<br />(ex: `_1d52e`). | No |
|
||||
| `sticky.`<br />`cookie.httpOnly` | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind of the main service is **Service**. | false | No |
|
||||
| `sticky.`<br />`cookie.secure` | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind of the main service is **Service**. | false | No |
|
||||
| `sticky.`<br />`cookie.sameSite` | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy.<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind of the main service is **Service**. | "" | No |
|
||||
| `sticky.`<br />`cookie.maxAge` | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind of the main service is **Service**. | 0 | No |
|
||||
| `strategy` | Load balancing strategy between the main service's servers.<br />RoundRobin is the only supported value yet.<br />Evaluated only if the kind of the main service is **Service**. | "RoundRobin" | No |
|
||||
| `weight` | Service weight.<br />To use only to refer to WRR TraefikService | "" | No |
|
||||
| `nativeLB` | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br />Evaluated only if the kind of the main service is **Service**. | false | No |
|
||||
| `nodePortLB` | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind of the main service is **Service**. | false | No |
|
||||
| `maxBodySize` | Maximum size allowed for the body of the request.<br />If the body is larger, the request is not mirrored.<br />-1 means unlimited size. | -1 | No |
|
||||
| `mirrors` | List of mirrored services to target.<br /> It can be any combination of TraefikService and [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). <br />More information [here](#services). | | No |
|
||||
| `mirrors[m].`<br />`kind` | Kind of the mirrored service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br />- **TraefikService**: Traefik Service.<br />More information [here](#services) | "" | No |
|
||||
| `mirrors[m].`<br />`name` | Mirrored service name.<br />The character `@` is not authorized. | "" | Yes |
|
||||
| `mirrors[m].`<br />`namespace` | Mirrored service namespace.<br />More information [here](#services). | "" | No |
|
||||
| `mirrors[m].`<br />`port` | Mirrored service port (number or port name).<br />Evaluated only if the kind of the mirrored service is **Service**. | "" | No |
|
||||
| `mirrors[m].`<br />`percent` | Part of the traffic to mirror in percent (from 0 to 100) | 0 | No |
|
||||
| `mirrors[m].`<br />`responseForwarding.`<br />`flushInterval` | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind of the mirrored service is **Service**. | 100ms | No |
|
||||
| `mirrors[m].`<br />`scheme` | Scheme to use for the request to the mirrored service.<br />Evaluated only if the kind of the mirrored service is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||
| `mirrors[m].`<br />`serversTransport` | Name of ServersTransport resource to use to configure the transport between Traefik and the mirrored service servers.<br />Evaluated only if the kind of the mirrored service is **Service**. | "" | No |
|
||||
| `mirrors[m].`<br />`passHostHeader` | Forward client Host header to the mirrored service servers.<br />Evaluated only if the kind of the mirrored service is **Service**. | true | No |
|
||||
| `mirrors[m].`<br />`healthCheck.scheme` | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.mode` | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "http" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.path` | Server URL path for the health check endpoint.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.interval` | Frequency of the health check calls.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "100ms" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.method` | HTTP method for the health check endpoint.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "GET" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.status` | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind of the mirrored service is **Service**. | | No |
|
||||
| `mirrors[m].`<br />`healthCheck.port` | URL port for the health check endpoint.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | | No |
|
||||
| `mirrors[m].`<br />`healthCheck.timeout` | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "5s" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.hostname` | Value in the Host header of the health check request.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | "" | No |
|
||||
| `mirrors[m].`<br />`healthCheck.`<br />`followRedirect` | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | true | No |
|
||||
| `mirrors[m].`<br />`healthCheck.headers` | Map of header to send to the health check endpoint<br />Evaluated only if the kind of the mirrored service is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type [ExternalName](#services). | | No |
|
||||
| `mirrors[m].`<br />`sticky.`<br />`cookie.name` | Name of the cookie used for the stickiness.<br />When sticky sessions are enabled, a `Set-Cookie` header is set on the initial response to let the client know which server handles the first response.<br />On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set.<br />If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).<br />Evaluated only if the kind of the mirrored service is **Service**. | "" | No |
|
||||
| `mirrors[m].`<br />`sticky.`<br />`cookie.httpOnly` | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind of the mirrored service is **Service**. | false | No |
|
||||
| `mirrors[m].`<br />`sticky.`<br />`cookie.secure` | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind of the mirrored service is **Service**. | false | No |
|
||||
| `mirrors[m].`<br />`sticky.`<br />`cookie.sameSite` | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy.<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind of the mirrored service is **Service**. | "" | No |
|
||||
| `mirrors[m].`<br />`sticky.`<br />`cookie.maxAge` | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind of the mirrored service is **Service**. | 0 | No |
|
||||
| `mirrors[m].`<br />`strategy` | Load balancing strategy between the servers.<br />RoundRobin is the only supported value yet.<br />Evaluated only if the kind of the mirrored service is **Service**. | "RoundRobin" | No |
|
||||
| `mirrors[m].`<br />`weight` | Service weight.<br />To use only to refer to WRR TraefikService | "" | No |
|
||||
| `mirrors[m].`<br />`nativeLB` | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br />Evaluated only if the kind of the mirrored service is **Service**. | false | No |
|
||||
| `mirrors[m].`<br />`nodePortLB` | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind of the mirrored service is **Service**. | false | No |
|
||||
| `mirrorBody` | Defines whether the request body should be mirrored. | true | No |
|
@ -0,0 +1,229 @@
|
||||
---
|
||||
title: "Kubernetes IngressRouteTCP"
|
||||
description: "An IngressRouteTCP is a Traefik CRD is in charge of connecting incoming TCP connections to the Services that can handle them."
|
||||
---
|
||||
|
||||
`IngressRouteTCP` is the CRD implementation of a [Traefik TCP router](../../../tcp/router/rules-and-priority.md).
|
||||
|
||||
Before creating `IngressRouteTCP` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `IngressRouteTCP` kind and other Traefik-specific resources.
|
||||
|
||||
!!! note "General"
|
||||
If both HTTP routers and TCP routers are connected to the same EntryPoint, the TCP routers will apply before the HTTP routers. If no matching route is found for the TCP routers, then the HTTP routers will take over.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
You can declare an `IngressRouteTCP` as detailed below:
|
||||
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: ingressroutetcpfoo
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- footcp
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
priority: 10
|
||||
middlewares:
|
||||
- name: middleware1
|
||||
namespace: default
|
||||
services:
|
||||
- name: foo
|
||||
port: 8080
|
||||
weight: 10
|
||||
proxyProtocol:
|
||||
version: 1
|
||||
serversTransport: transport
|
||||
nativeLB: true
|
||||
nodePortLB: true
|
||||
tls: false
|
||||
|
||||
tls:
|
||||
secretName: supersecret
|
||||
options:
|
||||
name: opt
|
||||
namespace: default
|
||||
certResolver: foo
|
||||
domains:
|
||||
- main: example.net
|
||||
sans:
|
||||
- a.example.net
|
||||
- b.example.net
|
||||
passthrough: false
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|-------------------------------------|-----------------------------|-------------------------------------------|-----------------------|
|
||||
| `entryPoints` | List of entrypoints names. | | No |
|
||||
| `routes` | List of routes. | | Yes |
|
||||
| `routes[n].match` | Defines the [rule](../../../tcp/router/rules-and-priority.md#rules) of the underlying router. | | Yes |
|
||||
| `routes[n].priority` | Defines the [priority](../../../tcp/router/rules-and-priority.md#priority) to disambiguate rules of the same length, for route matching. | | No |
|
||||
| `routes[n].middlewares[n].name` | Defines the [MiddlewareTCP](./middlewaretcp.md) name. | | Yes |
|
||||
| `routes[n].middlewares[n].namespace` | Defines the [MiddlewareTCP](./middlewaretcp.md) namespace. | ""| No|
|
||||
| `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions. | | No |
|
||||
| `routes[n].services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). | | Yes |
|
||||
| `routes[n].services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port.| | Yes |
|
||||
| `routes[n].services[n].weight` | Defines the weight to apply to the server load balancing. | 1 | No |
|
||||
| `routes[n].services[n].proxyProtocol` | Defines the [PROXY protocol](../../../../install-configuration/entrypoints.md#proxyprotocol-and-load-balancers) configuration. | | No |
|
||||
| `routes[n].services[n].proxyProtocol.version` | Defines the [PROXY protocol](../../../../install-configuration/entrypoints.md#proxyprotocol-and-load-balancers) version. | | No |
|
||||
| `routes[n].services[n].serversTransport` | Defines the [ServersTransportTCP](./serverstransporttcp.md).<br />The `ServersTransport` namespace is assumed to be the [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) namespace. | | No |
|
||||
| `routes[n].services[n].nativeLB` | Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. See [here](#nativelb) for more information. | false | No |
|
||||
| `routes[n].services[n].nodePortLB` | Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is `NodePort`. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. | false | No |
|
||||
| `tls` | Defines [TLS](../../../../install-configuration/tls/certificate-resolvers/overview.md) certificate configuration. | | No |
|
||||
| `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace). | "" | No |
|
||||
| `tls.options` | Defines the reference to a [TLSOption](../http/tlsoption.md). | "" | No |
|
||||
| `tls.options.name` | Defines the [TLSOption](../http/tlsoption.md) name. | "" | No |
|
||||
| `tls.options.namespace` | Defines the [TLSOption](../http/tlsoption.md) namespace. | "" | No |
|
||||
| `tls.certResolver` | Defines the reference to a [CertResolver](../../../../install-configuration/tls/certificate-resolvers/overview.md). | "" | No |
|
||||
| `tls.domains` | List of domains. | "" | No |
|
||||
| `tls.domains[n].main` | Defines the main domain name. | "" | No |
|
||||
| `tls.domains[n].sans` | List of SANs (alternative domains). | "" | No |
|
||||
| `tls.passthrough` | If `true`, delegates the TLS termination to the backend. | false | No |
|
||||
|
||||
### ExternalName Service
|
||||
|
||||
Traefik connect to a backend with a domain and a port. However, Kubernetes [ExternalName Service](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) can be defined without any port. Accordingly, Traefik supports defining a port in two ways:
|
||||
|
||||
- only on `IngressRouteTCP` service
|
||||
- on both sides, you'll be warned if the ports don't match, and the `IngressRouteTCP` service port is used
|
||||
|
||||
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||
|
||||
=== "Ports defined on Resource"
|
||||
|
||||
```yaml tab="IngressRouteTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
```
|
||||
|
||||
=== "Port defined on the Service"
|
||||
|
||||
```yaml tab="IngressRouteTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
=== "Port defined on both sides"
|
||||
|
||||
```yaml tab="IngressRouteTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
### NativeLB
|
||||
|
||||
To avoid creating the server load-balancer with the pods IPs and use Kubernetes Service `clusterIP` directly, one should set the `NativeLB` option to true. By default, `NativeLB` is false.
|
||||
|
||||
```yaml tab="IngressRouteTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
services:
|
||||
- name: svc
|
||||
port: 80
|
||||
# Here, nativeLB instructs to build the servers load balancer with the Kubernetes Service clusterIP only.
|
||||
nativeLB: true
|
||||
```
|
||||
|
||||
```yaml tab="Service"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc
|
||||
namespace: default
|
||||
spec:
|
||||
type: ClusterIP
|
||||
...
|
||||
```
|
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "Kubernetes MiddlewareTCP"
|
||||
description: "Learn how to configure a Traefik Proxy Kubernetes Middleware to reach TCP Services, which handle incoming requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
`MiddlewareTCP` is the CRD implementation of a [Traefik TCP middleware](../../../tcp/middlewares/overview.md).
|
||||
|
||||
Before creating `MiddlewareTCP` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `MiddlewareTCP` kind and other Traefik-specific resources.
|
||||
|
||||
!!! tip "Cross-provider namespace"
|
||||
As Kubernetes also has its own notion of namespace, one should not confuse the kubernetes namespace of a resource (in the reference to the middleware) with the [provider namespace](../../../../install-configuration/providers/overview.md#provider-namespace), when the definition of the middleware comes from another provider. In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored. Additionally, when you want to reference a Middleware from the CRD Provider, you have to append the namespace of the resource in the resource-name as Traefik appends the namespace internally automatically.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="MiddlewareTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```yaml tab="IngressRouteTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`example.com`) && PathPrefix(`/allowlist`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: ipallowlist
|
||||
namespace: foo
|
||||
```
|
||||
|
||||
More information about available TCP middlewares in the dedicated [middlewares section](../../../tcp/middlewares/overview.md).
|
@ -0,0 +1,51 @@
|
||||
---
|
||||
title : 'ServersTransportTCP'
|
||||
description : 'Understand the service routing configuration for the Kubernetes ServerTransportTCP & Traefik CRD'
|
||||
---
|
||||
|
||||
`ServersTransportTCP` is the CRD implementation of [ServersTransportTCP](../../../tcp/serverstransport.md).
|
||||
|
||||
Before creating `ServersTransportTCP` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `ServersTransportTCP` kind and other Traefik-specific resources.
|
||||
|
||||
!!! tip "Default serversTransportTCP"
|
||||
If no `serversTransportTCP` is specified, the `default@internal` will be used. The `default@internal` `serversTransportTCP` is created from the install configuration (formerly known as static configuration).
|
||||
|
||||
!!! note "ServersTransport reference"
|
||||
By default, the referenced `ServersTransportTCP` CRD must be defined in the same Kubernetes service namespace.
|
||||
|
||||
To reference a `ServersTransportTCP` CRD from another namespace, the value must be of form `namespace-name@kubernetescrd`, and the `allowCrossNamespace` option must be enabled.
|
||||
|
||||
If the `ServersTransportTCP` CRD is defined in another provider the cross-provider format `name@provider` should be used.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="ServersTransportTCP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: ServersTransportTCP
|
||||
metadata:
|
||||
name: mytransport
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
tls:
|
||||
serverName: example.org
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|-------------------------------------|-----------------------------|-------------------------------------------|-----------------------|
|
||||
| `dialTimeout` | The amount of time to wait until a connection to a server can be established. If zero, no timeout exists. | 30s | No |
|
||||
| `dialKeepAlive` | The interval between keep-alive probes for an active network connection.<br />If this option is set to zero, keep-alive probes are sent with a default value (currently 15 seconds),<br />if supported by the protocol and operating system. Network protocols or operating systems that do not support keep-alives ignore this field.<br />If negative, keep-alive probes are turned off.| 15s | No |
|
||||
| `terminationDelay` | Defines the delay to wait before fully terminating the connection, after one connected peer has closed its writing capability.| 100ms | No |
|
||||
| `tls.serverName` | ServerName used to contact the server. | "" | No |
|
||||
| `tls.insecureSkipVerify` | Controls whether the server's certificate chain and host name is verified. | false | No |
|
||||
| `tls.peerCertURI` | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
|
||||
| `tls.rootCAsSecrets` | Defines the set of root certificate authorities to use when verifying server certificates.<br />The CA secret must contain a base64 encoded certificate under either a `tls.ca` or a `ca.crt` key.| "" | No |
|
||||
| `tls.certificatesSecrets` | Certificates to present to the server for mTLS.| "" | No |
|
||||
| `spiffe` | Configures [SPIFFE](../../../../install-configuration/tls/spiffe.md) options. | "" | No |
|
||||
| `spiffe.ids` | Defines the allowed SPIFFE IDs. This takes precedence over the SPIFFE `trustDomain`. |""| No |
|
||||
| `spiffe.trustDomain` | Defines the allowed SPIFFE trust domain. | "" | No |
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "TLSOption"
|
||||
description: "TLS Options in Traefik Proxy"
|
||||
---
|
||||
|
||||
--8<-- "content/reference/routing-configuration/kubernetes/crd/http/tlsoption.md"
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "TLSStore"
|
||||
description: "TLS Store in Traefik Proxy"
|
||||
---
|
||||
|
||||
--8<-- "content/reference/routing-configuration/kubernetes/crd/http/tlsstore.md"
|
@ -0,0 +1,182 @@
|
||||
---
|
||||
title: "IngressRouteUDP"
|
||||
description: "Understand the routing configuration for the Kubernetes IngressRouteUDP & Traefik CRD"
|
||||
---
|
||||
|
||||
`IngressRouteUDP` is the CRD implementation of a [Traefik UDP router](../../../udp/router/rules-priority.md).
|
||||
|
||||
Before creating `IngressRouteUDP` objects, you need to apply the [Traefik Kubernetes CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions) to your Kubernetes cluster.
|
||||
|
||||
This registers the `IngressRouteUDP` kind and other Traefik-specific resources.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="IngressRouteUDP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: ingressrouteudpfoo
|
||||
namespace: apps
|
||||
spec:
|
||||
entryPoints:
|
||||
- fooudp # The entry point where Traefik listens for incoming traffic.
|
||||
routes:
|
||||
- services:
|
||||
- name: foo # The name of the Kubernetes Service to route to.
|
||||
port: 8080
|
||||
weight: 10
|
||||
nativeLB: true # Enables native load balancing between pods.
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|------------------------------------|-----------------------------|-------------------------------------------|-----------------------|
|
||||
| `entryPoints` | List of entrypoints names. | | No |
|
||||
| ` routes ` | List of routes. | | Yes |
|
||||
| `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions. See [here](#externalname-service) for `ExternalName Service` setup. | | No |
|
||||
| `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). | | Yes |
|
||||
| `routes[n].services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port.| | Yes |
|
||||
| `routes[n].services[n].weight` | Defines the weight to apply to the server load balancing. | 1 | No |
|
||||
| `routes[n].services[n].nativeLB` | Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. | false | No |
|
||||
| `routes[n].services[n].nodePortLB` | Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. See [here](#nativelb) for more information. | false | No |
|
||||
|
||||
### ExternalName Service
|
||||
|
||||
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) could be defined without any port. Accordingly, Traefik supports defining a port in two ways:
|
||||
|
||||
- only on `IngressRouteUDP` service
|
||||
- on both sides, you'll be warned if the ports don't match, and the `IngressRouteUDP` service port is used
|
||||
|
||||
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||
|
||||
=== "Ports defined on Resource"
|
||||
|
||||
```yaml tab="IngressRouteUDP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
```
|
||||
|
||||
=== "Port defined on the Service"
|
||||
|
||||
```yaml tab="IngressRouteUDP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
=== "Port defined on both sides"
|
||||
|
||||
```yaml tab="IngressRouteUDP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- match: Host(`example.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: external-svc
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Service ExternalName"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-svc
|
||||
namespace: apps
|
||||
|
||||
spec:
|
||||
externalName: external.domain
|
||||
type: ExternalName
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
### NativeLB
|
||||
|
||||
To avoid creating the server load-balancer with the pods IPs and use Kubernetes Service `clusterIP` directly, one should set the `NativeLB` option to true. By default, `NativeLB` is false.
|
||||
|
||||
```yaml tab="IngressRouteUDP"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
routes:
|
||||
- services:
|
||||
- name: svc
|
||||
port: 80
|
||||
# Here, nativeLB instructs to build the servers load balancer with the Kubernetes Service clusterIP only.
|
||||
nativeLB: true
|
||||
```
|
||||
|
||||
```yaml tab="Service"
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc
|
||||
namespace: default
|
||||
spec:
|
||||
type: ClusterIP
|
||||
...
|
||||
```
|
@ -0,0 +1,763 @@
|
||||
---
|
||||
title: "Traefik Kubernetes Gateway"
|
||||
description: "The Kubernetes Gateway API can be used as a provider for routing and load balancing in Traefik Proxy. View examples in the technical documentation."
|
||||
---
|
||||
|
||||
# Traefik & Kubernetes with Gateway API
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
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
|
||||
|
||||
A `Gateway` is a core resource in the Gateway API specification that defines the entry point for traffic into a Kubernetes cluster.
|
||||
It is linked to a `GatewayClass`, which specifies the controller responsible for managing and handling the traffic, ensuring that it is directed to the appropriate Kubernetes backend services.
|
||||
|
||||
The `GatewayClass` is a cluster-scoped resource typically defined by the infrastructure provider.
|
||||
The following `GatewayClass` defines that gateways attached to it must be managed by the Traefik controller.
|
||||
|
||||
```yaml tab="GatewayClass"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: GatewayClass
|
||||
metadata:
|
||||
name: traefik
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
```
|
||||
|
||||
Next, the following `Gateway` manifest configures the running Traefik controller to handle the incoming traffic.
|
||||
|
||||
!!! info "Listener ports"
|
||||
|
||||
Please note that `Gateway` listener ports must match the configured [EntryPoint ports](../../install-configuration/entrypoints.md) of the Traefik deployment.
|
||||
In case they do not match, an `ERROR` message is logged, and the resource status is updated accordingly.
|
||||
|
||||
```yaml tab="Gateway"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: traefik
|
||||
|
||||
# Only Routes from the same namespace are allowed.
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
- name: https
|
||||
protocol: HTTPS
|
||||
port: 443
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- name: secret-tls
|
||||
namespace: default
|
||||
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
- name: tcp
|
||||
protocol: TCP
|
||||
port: 3000
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
- name: tls
|
||||
protocol: TLS
|
||||
port: 3443
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- name: secret-tls
|
||||
namespace: default
|
||||
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
```
|
||||
|
||||
```yaml tab="Secret"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-tls
|
||||
namespace: default
|
||||
type: kubernetes.io/tls
|
||||
data:
|
||||
# Self-signed certificate for the whoami.localhost domain.
|
||||
tls.crt: |
|
||||
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZWakNDQXo2Z0F3SUJBZ0lVZUUrZG94aTUrMTBMVi9DaUdTMkt2Q1dJR1dZd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1JERUxNQWtHQTFVRUJoTUNSbEl4RFRBTEJnTlZCQWNNQkV4NWIyNHhGVEFUQmdOVkJBb01ERlJ5WVdWbQphV3NnVEdGaWN6RVBNQTBHQTFVRUF3d0dWMmh2WVcxcE1DQVhEVEkwTURjeE1ERTFNRGt3TjFvWUR6SXhNalF3Ck5qRTJNVFV3T1RBM1dqQkVNUXN3Q1FZRFZRUUdFd0pHVWpFTk1Bc0dBMVVFQnd3RVRIbHZiakVWTUJNR0ExVUUKQ2d3TVZISmhaV1pwYXlCTVlXSnpNUTh3RFFZRFZRUUREQVpYYUc5aGJXa3dnZ0lpTUEwR0NTcUdTSWIzRFFFQgpBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQ1pNNm1WNUJkV2V0QzZtdnp0YVBobFNjZ0ljbnd6Z3NsOEFxendEMk05ClJWVkZwRUxBbTh2OTNlRWtMZEY2ZnNkY0FhUXQxWlFDSFdYby9mTHBRNVVrUHh1djZNUCt2NG1KMHY4ZEtGWjcKUjcwaTVud1lCMkVlVkw2RUNZaWlxNmZ6VEtsa3F6U0QvNW93elN3L3pqa0dUYTBJdy92SDlhc0g3NEhqM1d0QQo3RythenZjaVlhQTZxK1dWYlZxNlBIanF6em9obEFuMkh1ano2aERqYWllc3ZMbHdBL0IvcmhEc0FLaCtpMHI4CkFKUTFqM0JiTGJuYkJyWmZqYnBJUjNhYVh5amkwK3RQWENnVTkzQmU5dm1LZTZTY0dSNy82T25tYmtTc0xjZFcKaFpVNzcrL2c4WllsZGhwS01nczc4ekJYUlh4bHlzSThHRUtqU1hud3k5WmZNT2RJNEpBTWNtT0lOaVlBY21abgpJTUJIa0xacFl3aUl0eFdseXVJcWxoZFpkSHNrTFdNSjBSTHUxRmhTMnBFV0NOZTM3VDBiOWhtNFg0OXJ1QWJ6Ckl1M01xSmczcXFIdGRMNGRkZ1JZRHNjMXd0cDJrR2dBZGxDaXJIclF6K1l4MEJNT1ZsZEczaG1SUUh5ZHEySHIKWW0xeEFDNWpMZ3FvaVZhY09wd0xKY21PcGsrZWVNQkNZNVo0ekNYN1hXeXdhVmNtMnN2aGlPMThCZFIraDloWQpiMkRNZDFCendDbE95endQcUlvQy9uNGRURG96Ry9GT3NySzgvNEZ4dzY2Q1ZmM3E4MzBNUHdSd2xDSzFDQjdGCjNQK3lKWkpPelRuK05QZ2dGQW9NaGZUYXBQWTFhUGlWajBzVG9vQjBaOGNFV1RkTnJxQU5tUGs5aDNoQjJwbjgKSndJREFRQUJvejR3UERBYkJnTlZIUkVFRkRBU2doQjNhRzloYldrdWJHOWpZV3hvYjNOME1CMEdBMVVkRGdRVwpCQlNGSjF4N01xdG9zQ3UwQmFWbEs1U054K2djampBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQVdCOVc1eWkzClRpTWpmSThhSCtMZW1wZjc4clhyeWJ6UXJvSXdEazhqQXhnc3Nrc2V2ZEtIaXJIZGJMZ0RoS2krbkJLeEQ5S2QKNWM4RS9VL1VHWUhxaUowTVUzYkpoeTVNM3oyaklKd1hFa3FuVVhRd0dBNzVyU0QxWVBkOTlWeVpuNEJVRlEwdwpCT3loOU5DS3Z3ZTgycUVlOWZmeU5iem5JUEMrNS9pekhaYlNQMEpwRzdtNFQ5TXljdHV1OTlsaVhmSVlCMU1PCkRFRUdpamxhZ3JvdTliVlpsNmovR2xCaVZpU0JVQXhaRlNqdFErV2RFODJaZlFRUFVWdXQrUEY0SEl0N1dmYlgKaUpZbjRsMytJSVczNStvbUZ5QjR5WUJNdU9SVWRsZ3V5N1ZieEU5OTdPdHYzTnpDOGJYcGtaQVM0TkVzQVVFdwpJZ3lOcTFCdExsb3dZdjZXY05HbkJ5RE1NRUMzdUYzNEcxQkJCTzFDRHUrYXBVdW5NbVhUWmU5WlkrbXh4U2Z2CnBZclhHTHBoT2t4ZitQalpMbEpqQVFlcTNxblMvWWtLQmtYQi9zb282ZVVLTTlybyt5RTVMbnFrV20wZXpQWmwKc2Z5NGpqZ0lJUHlUMHhhZ0YyWExzUSs0M3N4aDRYTEhmc3Z3Zis2QnJVK2trTnoydmc2M3duLzJDQUNVVms3bgphSDdwZzZyZGt4T2pOTDJjUGd6ZzhWaExXbkVYYjhhUVJlVjY1WnlRc0xta21oOXBlSFRpYXBUb2xWa0d6TDIwCm9pdExZc3ZUcnhUR2NRd3Jpd3FaT1I3WjEvVEJLVnVoYnp0emxlRjFHRk9LdE52UmNSREVBeWVlbnJDRzRRMmgKMnFNNFh1RFFKcjJrR095OEV0dnlYTitENkNZUkg0ck5vZUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
|
||||
tls.key: |
|
||||
LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRQ1pNNm1WNUJkV2V0QzYKbXZ6dGFQaGxTY2dJY253emdzbDhBcXp3RDJNOVJWVkZwRUxBbTh2OTNlRWtMZEY2ZnNkY0FhUXQxWlFDSFdYbwovZkxwUTVVa1B4dXY2TVArdjRtSjB2OGRLRlo3UjcwaTVud1lCMkVlVkw2RUNZaWlxNmZ6VEtsa3F6U0QvNW93CnpTdy96amtHVGEwSXcvdkg5YXNINzRIajNXdEE3RythenZjaVlhQTZxK1dWYlZxNlBIanF6em9obEFuMkh1anoKNmhEamFpZXN2TGx3QS9CL3JoRHNBS2graTByOEFKUTFqM0JiTGJuYkJyWmZqYnBJUjNhYVh5amkwK3RQWENnVQo5M0JlOXZtS2U2U2NHUjcvNk9ubWJrU3NMY2RXaFpVNzcrL2c4WllsZGhwS01nczc4ekJYUlh4bHlzSThHRUtqClNYbnd5OVpmTU9kSTRKQU1jbU9JTmlZQWNtWm5JTUJIa0xacFl3aUl0eFdseXVJcWxoZFpkSHNrTFdNSjBSTHUKMUZoUzJwRVdDTmUzN1QwYjlobTRYNDlydUFiekl1M01xSmczcXFIdGRMNGRkZ1JZRHNjMXd0cDJrR2dBZGxDaQpySHJReitZeDBCTU9WbGRHM2htUlFIeWRxMkhyWW0xeEFDNWpMZ3FvaVZhY09wd0xKY21PcGsrZWVNQkNZNVo0CnpDWDdYV3l3YVZjbTJzdmhpTzE4QmRSK2g5aFliMkRNZDFCendDbE95endQcUlvQy9uNGRURG96Ry9GT3NySzgKLzRGeHc2NkNWZjNxODMwTVB3UndsQ0sxQ0I3RjNQK3lKWkpPelRuK05QZ2dGQW9NaGZUYXBQWTFhUGlWajBzVApvb0IwWjhjRVdUZE5ycUFObVBrOWgzaEIycG44SndJREFRQUJBb0lDQUVCa2dKRXA3ODAvamVBQktQSTR2cjhFCkJmblc5UEZKdFpwVUhaQkJSM3NIVzFJTU9xcHVVWTJBNXhLbjEzWmZOemdxMEhFYlpqeUZVc0pkaXU0VW8razYKUlU3b3pRaVVSU0VTK0h1dTZycWlhcEx5d1pIditCZ2hrbm80NzU4Lyt6VytNU3pJOFNmU0ZXTVJ1ZG1QdWxRMQo3ZGJUV1U2d3FaU0tUTlFUeXZMYzdnUHBuZUpybWtkTzNRNnppZ0RoVGdtVDFHRXNzZ3NxN3NzbXhMWnhkZithCnkyNlRtVkJ4UDFlUzV6OVpHTWxYRFBSK044RjdOTFVrMng3S21WT3NCZVBZdjN5bmlpNHZGQUhNQndWRFZadXAKWUlUajRpMjZIaVhtanlLM2t5T0F2anNWSElRMXh1QTBCZFROdC84WXRtYllJL005QitydVg0UDJiRFNUMktRKwo4TlN2Uk9wbVppcnBHZkY3bExMSGpJUjlTMFhCWDd6VDRoWnBRWnpqK3NEWnhDM2Y3TGIwRFlKYkp0TmlDYTQxCmNpTjhNUlNldzNneHZ0RVk0RzdnN3hjbkJNdjdNT3RwQTE3d2gvMHdLd0h0amYzSWh2TmIzdkZwT0k5d1FqSzYKSlRQMng4bENJV0tyalpObVN0UksreHJTN3hTOUZVdnBhSVlyclRLQkZWSmcyMURCYWI1L3hqRlBlQWxXejczSwpvVkhsa0hLdXNMSjZLczZzcXo0ZG9mbzg3dkFsUFJzTXRkZ1ZnZFIzNXhLTGtEWXNIbGxML3Z5dE9oSkNieXB5CkJqQm1TR0RMdzBDdWplaHVtU2czYjdSUGVTNk5rbHNqUEIrMVpzRjhpVGdCcjMyM1hvTmNha2dhWWVYQlg4NFAKaE1WZHUxWk1rbXJZMWhXTzEydnhBb0lCQVFEWU5Vb2xCMkhsdWlDcVFqdmU4UFNhV0YxRmhwNUlOMGJIZEppeApIdkhqMkplVHJ6V1pUZFlIdFNJR2RzalhTOTBESXo2bXJhMW9YZXFRYlgrODVlOUFQQkZnRTJmNU5uTzBCSVVJCk5hMXRiVGpIOUhjRGRzQmJKUkZwYnk1ODZUb3lhdFY3bS9zcjVpQUZlZFMyenFOTm1XUmZOdllZS2xselZoSEUKdUd4ZjZxMHJTWktVQUhja2s1bU5Yais3WFhZaTgyemErVEE3ZjBDVm5OamR3OXFpd3B2aTJKTFB2SnA0bWt6KwpyMEN1RW9yV2NhMUdTL2hTVWdXemw3NzhQdlRpZFI2RW4zMDB2ZlIyTE84aG1xRjhVL3Bpb2UrTDVjSllRNnNKCk1YMngrYThzWFFpZ3dwdG02aUNxQ2FuS3ExN3NUZS9RTmQ1czdwb3ZOaHVKOHd3dEFvSUJBUUMxWmM5ZktPUFgKVzZSN1VoaHRRcmhIc3htQnRIQ1BuNWRLbjN5MElNNWRBaEFSdFZDV1U0M0hOTHpCNW1LbjU2dnZrSVNFaXdBbAoxTGhuY2I3YXQ2cHpTSlZtMm5oTDhjeUZrdGQrNzVyL1FHNFlpNnZQbHNBODV5ZXZpZDhZcWswaHdaZXExY05xCmxETUN3NWsrV0drckM2VW5jZXNIc2FWbDJTUGdZV1c1L3I1NnVxUnBsaVFka1EyZmlEYWRyblVueU8ycHg3bFMKVG1HemZaNmtzTWh2MlZFR1NPRm05aUo0dWlPb0xyZVhoU1RQRmxTdjdZUTZSWWtSaGgwT0tqdXM5bXZacEIxWApjcytYN0UyVTNlM0RZelpCR0NFdmxxaFNWTFRScjdIN21pMWxUMEozR0RzbDdiUk9xOE50WVdQa3hhSlNCUnQ5Ck9TcTlkTm9CcGRvakFvSUJBQ2lQdnN3NW1WVW0yUS80QXhGdE5RWnJ3M3ZTcUlrMXpaS0h2a21rVzQ3NlNGMk4KaGttdmY1TE1tWWlLNmx6eHY1SGlIOVBYUzJ3RUNvaHo4bjMyeVM3TTFobW5LbDlucHNkRC9jMHZmTXpGcTl4ZgpjYUIxdTlxZGxxbW9FUm1nQzZuL3Z2TkVyUmRzUWQrbEhwSDVMRXZYbGl3Q3ZLS0Y5MmdhNHBSOFlPQ1J2MUVhCnFXUVl2a0ZmYTNSSkZUM0taK3BncnJCYUJZRnoreUxXWFIwbHJEUFN2TG9QRldQaHB6MHUvWGplV2cwT0wzdlIKc2NjNVkybldOM21jNDFpaFd3SE5KUitPYUVmbnh5QVFpQUJPNlRMUThtMWtvZk1sOUpMb2h3TGZoUXhKb21KNQpSYkFiTWxwWlhDMXFTSzliL1IvcDh5NmxuSWZsTDRuaDVjSzRsVFVDZ2dFQUpSSHVSQU1tTksrTXVJcjVaUEs2Cm1DUjR0UEg4QXMzWmJDMlZuWFlLMWlVQ3hhdXBFVjkzM05yaExEcjV0Rmg2NFpWR0Q1UWNicDYvSkp5eEpSOWQKblB1YlZJNlhBT1lrSnJQd2lBZE5SSmFWS1R6NTJvMXpNYjhIZEM4WHdZR2tDNTcxY0xzSW1YSTV6bm5NaWxvaworK0FBVzBSRGhLb0FKQVV3K0x6T3ZpamFJbGljR3R2TSs2SFdCK0VkVURJRHpTS1p0eFdTd01nMTNTbHh6elExCmNlNFdTZE9CQkxxT0p0L2JRNVp3ZkcyQUxUWGlEcVhhWE5JekJickRtMDUwTFkrYVVMcmlLQ25WVkxXODBReGQKZDQyQjIrR2pmb2NxVk5Ec3R1RlIzUm9QNXVGQXN2Zm50b09TVW5WMWxaZk9nMFVFUEFEQk1tRUpZL2hLU1FYcwp3d0tDQVFBNWQya2hFQ1c1V3QrMzRYWnl1b3NFTjZ4UDExbC96VDRBZjhGSWtQLzlkb0JXRnBhc28zbG1NcXZHCmhPeFErbnZBSjFhNzhZRjA4N3p1UC9DZkQ0UElOUTV4YzZHMDNQdG5JOVNVT0dpMDB4Zlg5MU5NMHBHYWJqb0QKZ0RqVzJxSkJDaVB5N0RIR1RlZkU5eUNUbkhrY1NBbWllVGc3aGFyeEZPOUREZTJKbzhKQXV2SHI1aGVxazVIcgpLYlgzTy9vNUMwcWVnYW1rWVRLcHZzV2VFdXhkY2l5LzFQd3NnV3BuV1JPWllQNENrSkJweEx1bDNVamVSY3dkCnRhcjBJYU52WlV2NFd4U0JZdWVHMDFyYUd2SDZtTTcyTEExR3MrMytwTnZwUVo3bGo2S09tcFlhQUlhemVxY2MKTjJjT2R5U1RqZmQ5OFlNVFAxbmIyK3N1Yy91VAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
```
|
||||
|
||||
## Exposing a Route
|
||||
|
||||
Once a `Gateway` is deployed (see [Deploying a Gateway](#deploying-a-gateway)) `HTTPRoute`, `TCPRoute`,
|
||||
and/or `TLSRoute` resources must be deployed to forward some traffic to Kubernetes backend [services](https://kubernetes.io/docs/concepts/services-networking/service/).
|
||||
|
||||
!!! info "Attaching to Gateways"
|
||||
|
||||
As demonstrated in the following examples, a Route resource must be configured with `ParentRefs` that reference the parent `Gateway` it should be associated with.
|
||||
|
||||
### HTTP/HTTPS
|
||||
|
||||
The `HTTPRoute` is a core resource in the Gateway API specification, designed to define how HTTP traffic should be routed within a Kubernetes cluster.
|
||||
It allows the specification of routing rules that direct HTTP requests to the appropriate Kubernetes backend services.
|
||||
|
||||
For more details on the resource and concepts, check out the Kubernetes Gateway API [documentation](https://gateway-api.sigs.k8s.io/api-types/httproute/).
|
||||
|
||||
For example, the following manifests configure a whoami backend and its corresponding `HTTPRoute`,
|
||||
reachable through the [deployed `Gateway`](#deploying-a-gateway) at the `http://whoami.localhost` address.
|
||||
|
||||
```yaml tab="HTTPRoute"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami-http
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: http
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- whoami.localhost
|
||||
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
namespace: default
|
||||
port: 80
|
||||
```
|
||||
|
||||
```yaml tab="Whoami deployment"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami
|
||||
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami
|
||||
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
To secure the connection with HTTPS and redirect non-secure request to the secure endpoint,
|
||||
we will update the above `HTTPRoute` manifest to add a `RequestRedirect` filter,
|
||||
and add a new `HTTPRoute` which binds to the https `Listener` and forward the traffic to the whoami backend.
|
||||
|
||||
```yaml tab="HTTRoute (HTTP)"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami-http
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: http
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- whoami.localhost
|
||||
|
||||
rules:
|
||||
- filters:
|
||||
- type: RequestRedirect
|
||||
requestRedirect:
|
||||
scheme: https
|
||||
```
|
||||
|
||||
```yaml tab="HTTRoute (HTTPS)"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami-https
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: https
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- whoami.localhost
|
||||
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
namespace: default
|
||||
port: 80
|
||||
```
|
||||
|
||||
Once everything is deployed, sending a `GET` request to the HTTP and HTTPS endpoints should return the following responses:
|
||||
|
||||
??? success "Response"
|
||||
|
||||
```shell
|
||||
$ curl -I http://whoami.localhost
|
||||
|
||||
HTTP/1.1 302 Found
|
||||
Location: https://whoami.localhost/
|
||||
Date: Thu, 11 Jul 2024 15:11:31 GMT
|
||||
Content-Length: 5
|
||||
|
||||
$ curl -k https://whoami.localhost
|
||||
|
||||
Hostname: whoami-697f8c6cbc-2krl7
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.1.5
|
||||
IP: fe80::60ed:22ff:fe10:3ced
|
||||
RemoteAddr: 10.42.2.4:44682
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.localhost
|
||||
User-Agent: curl/7.87.1-DEV
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.42.1.0
|
||||
X-Forwarded-Host: whoami.localhost
|
||||
X-Forwarded-Port: 443
|
||||
X-Forwarded-Proto: https
|
||||
X-Forwarded-Server: traefik-6b66d45748-ns8mt
|
||||
X-Real-Ip: 10.42.1.0
|
||||
```
|
||||
|
||||
#### Using Traefik middleware as HTTPRoute filter
|
||||
|
||||
An HTTP [filter](https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional) is an `HTTPRoute` component which enables the modification of HTTP requests and responses as they traverse the routing infrastructure.
|
||||
|
||||
There are three types of filters:
|
||||
|
||||
- **Core:** Mandatory filters for every Gateway controller, such as `RequestHeaderModifier` and `RequestRedirect`.
|
||||
- **Extended:** Optional filters for Gateway controllers, such as `ResponseHeaderModifier` and `RequestMirror`.
|
||||
- **ExtensionRef:** Additional filters provided by the Gateway controller. In Traefik, these are the [HTTP middlewares](../http/middlewares/overview.md) supported through the [Middleware CRD](../kubernetes/crd/http/middleware.md).
|
||||
|
||||
!!! info "ExtensionRef Filters"
|
||||
|
||||
To use Traefik middlewares as `ExtensionRef` filters, the Kubernetes IngressRoute provider must be enabled in the static configuration, as detailed in the [documentation](../../install-configuration/providers/kubernetes/kubernetes-ingress.md).
|
||||
|
||||
For example, the following manifests configure an `HTTPRoute` using the Traefik `AddPrefix` middleware,
|
||||
reachable through the [deployed `Gateway`](#deploying-a-gateway) at the `http://whoami.localhost` address:
|
||||
|
||||
```yaml tab="HTTRoute"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami-http
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: http
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- whoami.localhost
|
||||
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoami
|
||||
namespace: default
|
||||
port: 80
|
||||
|
||||
filters:
|
||||
- type: ExtensionRef
|
||||
extensionRef:
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
name: add-prefix
|
||||
```
|
||||
|
||||
```yaml tab="AddPrefix middleware"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: add-prefix
|
||||
namespace: default
|
||||
spec:
|
||||
addPrefix:
|
||||
prefix: /prefix
|
||||
```
|
||||
|
||||
```yaml tab="Whoami deployment"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami
|
||||
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Once everything is deployed, sending a `GET` request should return the following response:
|
||||
|
||||
??? success "Response"
|
||||
|
||||
```shell
|
||||
$ curl http://whoami.localhost
|
||||
|
||||
Hostname: whoami-697f8c6cbc-kw954
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.2.6
|
||||
IP: fe80::a460:ecff:feb6:3a56
|
||||
RemoteAddr: 10.42.2.4:54758
|
||||
GET /prefix/ HTTP/1.1
|
||||
Host: whoami.localhost
|
||||
User-Agent: curl/7.87.1-DEV
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.42.2.1
|
||||
X-Forwarded-Host: whoami.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: traefik-6b66d45748-ns8mt
|
||||
X-Real-Ip: 10.42.2.1
|
||||
```
|
||||
|
||||
### GRPC
|
||||
|
||||
The `GRPCRoute` is an extended resource in the Gateway API specification, designed to define how GRPC traffic should be routed within a Kubernetes cluster.
|
||||
It allows the specification of routing rules that direct GRPC requests to the appropriate Kubernetes backend services.
|
||||
|
||||
For more details on the resource and concepts, check out the Kubernetes Gateway API [documentation](https://gateway-api.sigs.k8s.io/api-types/grpcroute/).
|
||||
|
||||
For example, the following manifests configure an echo backend and its corresponding `GRPCRoute`,
|
||||
reachable through the [deployed `Gateway`](#deploying-a-gateway) at the `echo.localhost:80` address.
|
||||
|
||||
```yaml tab="GRPCRoute"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: GRPCRoute
|
||||
metadata:
|
||||
name: echo
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: http
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- echo.localhost
|
||||
|
||||
rules:
|
||||
- matches:
|
||||
- method:
|
||||
type: Exact
|
||||
service: grpc.reflection.v1alpha.ServerReflection
|
||||
|
||||
- method:
|
||||
type: Exact
|
||||
service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho
|
||||
method: Echo
|
||||
|
||||
backendRefs:
|
||||
- name: echo
|
||||
namespace: default
|
||||
port: 3000
|
||||
```
|
||||
|
||||
```yaml tab="Echo deployment"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: echo
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: echo
|
||||
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: echo
|
||||
spec:
|
||||
containers:
|
||||
- name: echo-basic
|
||||
image: gcr.io/k8s-staging-gateway-api/echo-basic
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: GRPC_ECHO_SERVER
|
||||
value: "1"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: echo
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: echo
|
||||
|
||||
ports:
|
||||
- port: 3000
|
||||
```
|
||||
|
||||
Once everything is deployed, sending a GRPC request to the HTTP endpoint should return the following response:
|
||||
|
||||
??? success "Response"
|
||||
|
||||
```shell
|
||||
$ grpcurl -plaintext echo.localhost:80 gateway_api_conformance.echo_basic.grpcecho.GrpcEcho/Echo
|
||||
|
||||
{
|
||||
"assertions": {
|
||||
"fullyQualifiedMethod": "/gateway_api_conformance.echo_basic.grpcecho.GrpcEcho/Echo",
|
||||
"headers": [
|
||||
{
|
||||
"key": "x-real-ip",
|
||||
"value": "10.42.2.0"
|
||||
},
|
||||
{
|
||||
"key": "x-forwarded-server",
|
||||
"value": "traefik-74b4cf85d8-nkqqf"
|
||||
},
|
||||
{
|
||||
"key": "x-forwarded-port",
|
||||
"value": "80"
|
||||
},
|
||||
{
|
||||
"key": "x-forwarded-for",
|
||||
"value": "10.42.2.0"
|
||||
},
|
||||
{
|
||||
"key": "grpc-accept-encoding",
|
||||
"value": "gzip"
|
||||
},
|
||||
{
|
||||
"key": "user-agent",
|
||||
"value": "grpcurl/1.9.1 grpc-go/1.61.0"
|
||||
},
|
||||
{
|
||||
"key": "content-type",
|
||||
"value": "application/grpc"
|
||||
},
|
||||
{
|
||||
"key": "x-forwarded-host",
|
||||
"value": "echo.localhost:80"
|
||||
},
|
||||
{
|
||||
"key": ":authority",
|
||||
"value": "echo.localhost:80"
|
||||
},
|
||||
{
|
||||
"key": "accept-encoding",
|
||||
"value": "gzip"
|
||||
},
|
||||
{
|
||||
"key": "x-forwarded-proto",
|
||||
"value": "http"
|
||||
}
|
||||
],
|
||||
"authority": "echo.localhost:80",
|
||||
"context": {
|
||||
"namespace": "default",
|
||||
"pod": "echo-78f76675cf-9k7rf"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TCP
|
||||
|
||||
!!! info "Experimental Channel"
|
||||
|
||||
The `TCPRoute` resource described below is currently available only in the Experimental channel of the Gateway API specification.
|
||||
To use this resource, the [experimentalChannel](../../install-configuration/providers/kubernetes/kubernetes-gateway.md) configuration option must be enabled in the Traefik deployment.
|
||||
|
||||
The `TCPRoute` is a resource in the Gateway API specification designed to define how TCP traffic should be routed within a Kubernetes cluster.
|
||||
|
||||
For more details on the resource and concepts, check out the Kubernetes Gateway API [documentation](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1alpha2.TCPRoute).
|
||||
|
||||
For example, the following manifests configure a whoami backend and its corresponding `TCPRoute`,
|
||||
reachable through the [deployed `Gateway`](#deploying-a-gateway) at the `localhost:3000` address.
|
||||
|
||||
```yaml tab="TCPRoute"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
kind: TCPRoute
|
||||
metadata:
|
||||
name: whoami-tcp
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: tcp
|
||||
kind: Gateway
|
||||
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoamitcp
|
||||
namespace: default
|
||||
port: 3000
|
||||
```
|
||||
|
||||
```yaml tab="Whoami deployment"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoamitcp
|
||||
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoamitcp
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoamitcp
|
||||
args:
|
||||
- --port=:3000
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoamitcp
|
||||
ports:
|
||||
- port: 3000
|
||||
```
|
||||
|
||||
Once everything is deployed, sending the WHO command should return the following response:
|
||||
|
||||
??? success "Response"
|
||||
|
||||
```shell
|
||||
$ nc localhost 3000
|
||||
|
||||
WHO
|
||||
Hostname: whoamitcp-85d644bfc-ktzv4
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.1.4
|
||||
IP: fe80::b89e:85ff:fec2:7d21
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
!!! info "Experimental Channel"
|
||||
|
||||
The `TLSRoute` resource described below is currently available only in the Experimental channel of the Gateway API.
|
||||
Therefore, to use this resource, the [experimentalChannel](../../install-configuration/providers/kubernetes/kubernetes-gateway.md) option must be enabled.
|
||||
|
||||
The `TLSRoute` is a resource in the Gateway API specification designed to define how TLS (Transport Layer Security) traffic should be routed within a Kubernetes cluster.
|
||||
It specifies routing rules for TLS connections, directing them to appropriate backend services based on the SNI (Server Name Indication) of the incoming connection.
|
||||
|
||||
For more details on the resource and concepts, check out the Kubernetes Gateway API [documentation](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1alpha2.TLSRoute).
|
||||
|
||||
For example, the following manifests configure a whoami backend and its corresponding `TLSRoute`,
|
||||
reachable through the [deployed `Gateway`](#deploying-a-gateway) at the `localhost:3443` address via a secure connection with the `whoami.localhost` SNI.
|
||||
|
||||
```yaml tab="TLSRoute"
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
kind: TLSRoute
|
||||
metadata:
|
||||
name: whoami-tls
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik
|
||||
sectionName: tls
|
||||
kind: Gateway
|
||||
|
||||
hostnames:
|
||||
- whoami.localhost
|
||||
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoamitcp
|
||||
namespace: default
|
||||
port: 3000
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Whoami deployment"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoamitcp
|
||||
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoamitcp
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoamitcp
|
||||
args:
|
||||
- --port=:3000
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoamitcp
|
||||
ports:
|
||||
- port: 3000
|
||||
```
|
||||
|
||||
Once everything is deployed, sending the WHO command should return the following response:
|
||||
|
||||
??? success "Response"
|
||||
|
||||
```shell
|
||||
$ openssl s_client -quiet -connect localhost:3443 -servername whoami.localhost
|
||||
Connecting to ::1
|
||||
depth=0 C=FR, L=Lyon, O=Traefik Labs, CN=Whoami
|
||||
verify error:num=18:self-signed certificate
|
||||
verify return:1
|
||||
depth=0 C=FR, L=Lyon, O=Traefik Labs, CN=Whoami
|
||||
verify return:1
|
||||
|
||||
WHO
|
||||
Hostname: whoamitcp-85d644bfc-hnmdz
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.2.4
|
||||
IP: fe80::d873:20ff:fef5:be86
|
||||
```
|
||||
|
||||
## Native Load Balancing
|
||||
|
||||
By default, Traefik sends the traffic directly to the pod IPs and reuses the established connections to the backends for performance purposes.
|
||||
|
||||
It is possible to override this behavior and configure Traefik to send the traffic to the service IP.
|
||||
The Kubernetes service itself does the load balancing to the pods.
|
||||
It can be done with the annotation `traefik.io/service.nativelb` on the backend `Service`.
|
||||
|
||||
By default, NativeLB is `false`.
|
||||
|
||||
!!! info "Default value"
|
||||
|
||||
Note that it is possible to override the default value by using the option [`nativeLBByDefault`](../../install-configuration/providers/kubernetes/kubernetes-gateway.md) at the provider level.
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myservice
|
||||
namespace: default
|
||||
annotations:
|
||||
traefik.io/service.nativelb: "true"
|
||||
spec:
|
||||
[...]
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,617 @@
|
||||
---
|
||||
title: "Kubernetes Ingress Routing Configuration"
|
||||
description: "Understand the routing configuration for the Kubernetes Ingress Controller and Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Traefik & Kubernetes with Ingress
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
The Kubernetes Ingress 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.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: myingress
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
- path: /foo
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
## Annotations
|
||||
|
||||
!!! warning "Referencing resources in annotations"
|
||||
|
||||
In an annotation, when referencing a resource defined by another provider,
|
||||
the [provider namespace syntax](../../install-configuration/providers/overview.md#provider-namespace) must be used.
|
||||
|
||||
### On Ingress
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth@file,default-prefix@kubernetescrd
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.priority: "42"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.rulesyntax`"
|
||||
|
||||
See [rule syntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.rulesyntax: "v2"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.pathmatcher`"
|
||||
|
||||
Overrides the default router rule type used for a path.
|
||||
Only path-related matcher name should be specified: `Path`, `PathPrefix` or `PathRegexp`.
|
||||
|
||||
Default `PathPrefix`
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.pathmatcher: Path
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.tls`"
|
||||
|
||||
<!-- See [tls](../http/tls/tls-certificates.md) for more information. -->
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.tls.certresolver`"
|
||||
|
||||
<!-- See [certResolver](.) for more information. -->
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls.certresolver: myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.tls.domains.n.main`"
|
||||
|
||||
<!-- See [domains](.) for more information. -->
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls.domains.0.main: example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.tls.domains.n.sans`"
|
||||
|
||||
<!-- See [domains](.) for more information. -->
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls.domains.0.sans: test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.tls.options`"
|
||||
|
||||
See [options](../kubernetes/crd/http/tlsoption.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls.options: foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.observability.accesslogs`"
|
||||
|
||||
See [here](../http/router/observability.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.observability.accesslogs: true
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.observability.metrics`"
|
||||
|
||||
See [here](../http/router/observability.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.observability.metrics: true
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.observability.tracing`"
|
||||
|
||||
See [here](../http/router/observability.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.observability.tracing: true
|
||||
```
|
||||
|
||||
### On Service
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.nativelb`"
|
||||
|
||||
Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP.
|
||||
The Kubernetes Service itself does load-balance to the pods.
|
||||
Please note that, by default, Traefik reuses the established connections to the backends for performance purposes. This can prevent the requests load balancing between the replicas from behaving as one would expect when the option is set.
|
||||
By default, NativeLB is false.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.nativelb: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.nodeportlb`"
|
||||
|
||||
Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort.
|
||||
It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.
|
||||
By default, NodePortLB is false.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.nodeportlb: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.serversscheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.serversscheme: h2c
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.serverstransport`"
|
||||
|
||||
See [ServersTransport](../kubernetes/crd/http/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.serverstransport: foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.passhostheader`"
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.passhostheader: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.name`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie.name: foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.secure`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie.secure: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.samesite`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie.samesite: "none"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.httponly`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie.httponly: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.maxage`"
|
||||
|
||||
See [sticky sessions](../kubernetes/crd/http/traefikservice.md#stickiness-on-multiple-levels) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie.maxage: 42
|
||||
```
|
||||
|
||||
## TLS
|
||||
|
||||
### Enabling TLS via HTTP Options on Entrypoint
|
||||
|
||||
TLS can be enabled through the [HTTP options](../../install-configuration/entrypoints.md) of an Entrypoint:
|
||||
|
||||
```bash tab="CLI"
|
||||
# Static configuration
|
||||
--entryPoints.websecure.address=:443
|
||||
--entryPoints.websecure.http.tls
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Static configuration
|
||||
entryPoints:
|
||||
websecure:
|
||||
address: ':443'
|
||||
http:
|
||||
tls: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Static configuration
|
||||
[entryPoints.websecure]
|
||||
address = ":443"
|
||||
|
||||
[entryPoints.websecure.http.tls]
|
||||
```
|
||||
|
||||
This way, any Ingress attached to this Entrypoint will have TLS termination by default.
|
||||
|
||||
??? example "Configuring Kubernetes Ingress Controller with TLS on Entrypoint"
|
||||
|
||||
```yaml tab="RBAC"
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
resources:
|
||||
- ingresses
|
||||
- ingressclasses
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
resources:
|
||||
- ingresses/status
|
||||
verbs:
|
||||
- update
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: traefik-ingress-controller
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: traefik-ingress-controller
|
||||
namespace: default
|
||||
```
|
||||
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: myingress
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
- path: /foo
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
```yaml tab="Traefik"
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: traefik
|
||||
labels:
|
||||
app: traefik
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: traefik
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: traefik
|
||||
spec:
|
||||
serviceAccountName: traefik-ingress-controller
|
||||
containers:
|
||||
- name: traefik
|
||||
image: traefik:v3.2
|
||||
args:
|
||||
- --entryPoints.websecure.address=:443
|
||||
- --entryPoints.websecure.http.tls
|
||||
- --providers.kubernetesingress
|
||||
ports:
|
||||
- name: websecure
|
||||
containerPort: 443
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: traefik
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
app: traefik
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
name: websecure
|
||||
targetPort: 443
|
||||
```
|
||||
|
||||
```yaml tab="Whoami"
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
labels:
|
||||
app: traefiklabs
|
||||
name: whoami
|
||||
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
```
|
||||
|
||||
### Enabling TLS via Annotations
|
||||
|
||||
To enable TLS on the underlying router created from an Ingress, one should configure it through annotations:
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
```
|
||||
|
||||
For more options, please refer to the available [annotations](#on-ingress).
|
||||
|
||||
??? example "Configuring Kubernetes Ingress Controller with TLS"
|
||||
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: myingress
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
- path: /foo
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
### Certificates Management
|
||||
|
||||
??? example "Using a secret"
|
||||
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: production
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: example.net
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: service1
|
||||
port:
|
||||
number: 80
|
||||
# Only selects which certificate(s) should be loaded from the secret, in order to terminate TLS.
|
||||
# Doesn't enable TLS for that ingress (hence for the underlying router).
|
||||
# Please see the TLS annotations on ingress made for that purpose.
|
||||
tls:
|
||||
- secretName: supersecret
|
||||
```
|
||||
|
||||
```yaml tab="Secret"
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
```
|
||||
|
||||
TLS certificates can be managed in Secrets objects.
|
||||
|
||||
!!! info
|
||||
|
||||
Only TLS certificates provided by users can be stored in Kubernetes Secrets.
|
||||
[Let's Encrypt](../../install-configuration/tls/certificate-resolvers/acme.md) certificates cannot be managed in Kubernetes Secrets yet.
|
||||
|
||||
### Communication Between Traefik and Pods
|
||||
|
||||
!!! info "Routing directly to [Kubernetes services](https://kubernetes.io/docs/concepts/services-networking/service/ "Link to Kubernetes service docs")"
|
||||
|
||||
To route directly to the Kubernetes service,
|
||||
one can use the `traefik.ingress.kubernetes.io/service.nativelb` annotation on the Kubernetes service.
|
||||
It controls, when creating the load-balancer,
|
||||
whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP.
|
||||
|
||||
One alternative is to use an `ExternalName` service to forward requests to the Kubernetes service through DNS.
|
||||
To do so, one must allow external name services.
|
||||
|
||||
Traefik automatically requests endpoint information based on the service provided in the ingress spec.
|
||||
Although Traefik will connect directly to the endpoints (pods),
|
||||
it still checks the service port to see if TLS communication is required.
|
||||
|
||||
There are 3 ways to configure Traefik to use HTTPS to communicate with pods:
|
||||
|
||||
1. If the service port defined in the ingress spec is `443` (note that you can still use `targetPort` to use a different port on your pod).
|
||||
1. If the service port defined in the ingress spec has a name that starts with `https` (such as `https-api`, `https-web` or just `https`).
|
||||
1. If the service spec includes the annotation `traefik.ingress.kubernetes.io/service.serversscheme: https`.
|
||||
|
||||
If either of those configuration options exist, then the backend communication protocol is assumed to be TLS,
|
||||
and will connect via TLS automatically.
|
||||
|
||||
!!! info
|
||||
|
||||
Please note that by enabling TLS communication between traefik and your pods,
|
||||
you will have to have trusted certificates that have the proper trust chain and IP subject name.
|
||||
If this is not an option, you may need to skip TLS certificate verification.
|
||||
See the [`insecureSkipVerify` TLSOption](../kubernetes/crd/http/tlsoption.md) setting for more details.
|
||||
|
||||
## Global Default Backend Ingresses
|
||||
|
||||
Ingresses can be created that look like the following:
|
||||
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: cheese
|
||||
|
||||
spec:
|
||||
defaultBackend:
|
||||
service:
|
||||
name: stilton
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
This ingress follows the Global Default Backend property of ingresses.
|
||||
This will allow users to create a "default router" that will match all unmatched requests.
|
||||
|
||||
!!! info
|
||||
|
||||
Due to Traefik's use of priorities, you may have to set this ingress priority lower than other ingresses in your environment,
|
||||
to avoid this global ingress from satisfying requests that could match other ingresses.
|
||||
|
||||
To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,592 @@
|
||||
---
|
||||
title: "Traefik Consul Catalog Routing"
|
||||
description: "Learn how to use Consul Catalog as a provider for routing configurations in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Traefik & Consul Catalog
|
||||
|
||||
One of the best feature of Traefik is to delegate the routing configuration to the application level.
|
||||
With Consul Catalog, Traefik can leverage tags attached to a service to generate routing rules.
|
||||
|
||||
!!! warning "Tags & sensitive data"
|
||||
|
||||
We recommend to *not* use tags to store sensitive data (certificates, credentials, etc).
|
||||
Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc).
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "tags"
|
||||
|
||||
Tags are case-insensitive.
|
||||
|
||||
!!! tip "TLS Default Generated Certificates"
|
||||
|
||||
To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page.
|
||||
|
||||
### General
|
||||
|
||||
Traefik creates, for each consul Catalog service, a corresponding [service](../http/load-balancing/service.md) and [router](../http/router/rules-and-priority.md).
|
||||
|
||||
The Service automatically gets a server per instance in this consul Catalog service, and the router gets a default rule attached to it, based on the service name.
|
||||
|
||||
### Routers
|
||||
|
||||
To update the configuration of the Router automatically attached to the service, add tags starting with `traefik.routers.{name-of-your-choice}.` and followed by the option you want to change.
|
||||
|
||||
For example, to change the rule, you could add the tag ```traefik.http.routers.my-service.rule=Host(`example.com`)```.
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.rule=Host(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
See [ruleSyntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.priority=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.entrypoints=web,websecure
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.middlewares=auth,prefix,cb
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.options=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.accesslogs=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.metrics=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.tracing=true"
|
||||
```
|
||||
|
||||
### Services
|
||||
|
||||
To update the configuration of the Service automatically attached to the service,
|
||||
add tags starting with `traefik.http.services.{name-of-your-choice}.`, followed by the option you want to change.
|
||||
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false`.
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
Useful when the service exposes multiples ports.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.port=8080
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.scheme=http
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.weight`"
|
||||
|
||||
Overrides the default weight.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.weight=42
|
||||
```
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.passhostheader=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.hostname=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.interval=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.method`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.port=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.http.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`redirectscheme`](../http/middlewares/redirectscheme.md) named `my-redirect`, you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme: https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.http.middlewares.my-redirect.redirectscheme.scheme=https
|
||||
# Referencing a middleware
|
||||
traefik.http.routers.my-service.middlewares=my-redirect
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers, Middlewares and/or Services using tags.
|
||||
|
||||
??? example "Declaring TCP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)
|
||||
traefik.tcp.routers.my-router.tls=true
|
||||
traefik.tcp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "TCP and HTTP"
|
||||
|
||||
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||
You can declare both a TCP Router/Service and an HTTP Router/Service for the same consul service (but you have to do so manually).
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../tcp/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.rule=HostSNI(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.priority`"
|
||||
See [priority](../tcp/router/rules-and-priority.md#priority) for more information.
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.priority=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.options=mysoptions
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
See [Passthrough](../tcp/tls.md#passthrough) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.passthrough=true
|
||||
```
|
||||
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
|
||||
|
||||
Determines whether to use TLS when dialing with the backend.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version=1
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.tcp.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.tcp.middlewares.test-inflightconn.amount=10
|
||||
# Referencing a middleware
|
||||
traefik.tcp.routers.my-service.middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using tags.
|
||||
|
||||
??? example "Declaring UDP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.my-router.entrypoints=udp
|
||||
traefik.udp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "UDP and HTTP"
|
||||
|
||||
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
|
||||
You can declare both a UDP Router/Service and an HTTP Router/Service for the same consul service (but you have to do so manually).
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../udp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.service=myservice
|
||||
```
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.udp.services.myudpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
### Specific Provider Options
|
||||
|
||||
#### `traefik.enable`
|
||||
|
||||
```yaml
|
||||
traefik.enable=true
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the service by setting `traefik.enable` to true or false.
|
||||
|
||||
This option overrides the value of `exposedByDefault`.
|
||||
|
||||
#### `traefik.consulcatalog.connect`
|
||||
|
||||
```yaml
|
||||
traefik.consulcatalog.connect=true
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the service as a Connect capable one by setting `traefik.consulcatalog.connect` to true or false.
|
||||
|
||||
This option overrides the value of `connectByDefault`.
|
||||
|
||||
#### `traefik.consulcatalog.canary`
|
||||
|
||||
```yaml
|
||||
traefik.consulcatalog.canary=true
|
||||
```
|
||||
|
||||
When ConsulCatalog, in the context of a Nomad orchestrator,
|
||||
is a provider (of service registration) for Traefik,
|
||||
one might have the need to distinguish within Traefik between a [Canary](https://learn.hashicorp.com/tutorials/nomad/job-blue-green-and-canary-deployments#deploy-with-canaries) instance of a service, or a production one.
|
||||
For example if one does not want them to be part of the same load-balancer.
|
||||
|
||||
Therefore, this option, which is meant to be provided as one of the values of the `canary_tags` field in the Nomad [service stanza](https://www.nomadproject.io/docs/job-specification/service#canary_tags),
|
||||
allows Traefik to identify that the associated instance is a canary one.
|
||||
|
||||
#### Port Lookup
|
||||
|
||||
Traefik is capable of detecting the port to use, by following the default consul Catalog flow.
|
||||
That means, if you just expose lets say port `:1337` on the consul Catalog ui, traefik will pick up this port and use it.
|
@ -0,0 +1,696 @@
|
||||
---
|
||||
title: "Traefik Docker Routing Documentation"
|
||||
description: "This guide will teach you how to attach labels to your containers, to route traffic and load balance with Traefik and Docker."
|
||||
---
|
||||
|
||||
# Traefik & Docker
|
||||
|
||||
One of the best feature of Traefik is to delegate the routing configuration to the application level.
|
||||
With Docker, Traefik can leverage labels attached to a container to generate routing rules.
|
||||
|
||||
!!! warning "Labels & sensitive data"
|
||||
|
||||
We recommend to *not* use labels to store sensitive data (certificates, credentials, etc).
|
||||
Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc).
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
??? example "Configuring Docker & Deploying / Exposing one Service"
|
||||
|
||||
Enabling the docker provider
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
docker: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.docker]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--providers.docker=true
|
||||
```
|
||||
|
||||
Attaching labels to containers (in your docker compose file)
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- traefik.http.routers.my-container.rule=Host(`example.com`)
|
||||
```
|
||||
|
||||
??? example "Specify a Custom Port for the Container"
|
||||
|
||||
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- traefik.http.routers.my-container.rule=Host(`example.com`)
|
||||
# Tell Traefik to use the port 12345 to connect to `my-container`
|
||||
- traefik.http.services.my-service.loadbalancer.server.port=12345
|
||||
```
|
||||
|
||||
!!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`"
|
||||
By default, Traefik uses the first exposed port of a container.
|
||||
|
||||
Setting the label `traefik.http.services.xxx.loadbalancer.server.port`
|
||||
overrides that behavior.
|
||||
|
||||
??? example "Specifying more than one router and service per container"
|
||||
|
||||
Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router.
|
||||
|
||||
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- traefik.http.routers.www-router.rule=Host(`example-a.com`)
|
||||
- traefik.http.routers.www-router.service=www-service
|
||||
- traefik.http.services.www-service.loadbalancer.server.port=8000
|
||||
- traefik.http.routers.admin-router.rule=Host(`example-b.com`)
|
||||
- traefik.http.routers.admin-router.service=admin-service
|
||||
- traefik.http.services.admin-service.loadbalancer.server.port=9000
|
||||
```
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "Labels"
|
||||
|
||||
- Labels are case-insensitive.
|
||||
|
||||
!!! tip "TLS Default Generated Certificates"
|
||||
|
||||
To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page.
|
||||
|
||||
### General
|
||||
|
||||
Traefik creates, for each container, a corresponding [service](../http/load-balancing/service.md) and [router](../http/router/rules-and-priority.md).
|
||||
|
||||
The Service automatically gets a server per instance of the container,
|
||||
and the router automatically gets a rule defined by `defaultRule` (if no rule for it was defined in labels).
|
||||
|
||||
#### Service definition
|
||||
|
||||
--8<-- "content/routing/providers/service-by-label.md"
|
||||
|
||||
??? example "Automatic assignment with one Service"
|
||||
|
||||
With labels in a compose file
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
||||
# service myservice gets automatically assigned to router myproxy
|
||||
- "traefik.http.services.myservice.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
??? example "Automatic service creation with one Router"
|
||||
|
||||
With labels in a compose file
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# no service specified or defined and yet one gets automatically created
|
||||
# and assigned to router myproxy.
|
||||
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
||||
```
|
||||
|
||||
??? example "Explicit definition with one Service"
|
||||
|
||||
With labels in a compose file
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- traefik.http.routers.www-router.rule=Host(`example-a.com`)
|
||||
# Explicit link between the router and the service
|
||||
- traefik.http.routers.www-router.service=www-service
|
||||
- traefik.http.services.www-service.loadbalancer.server.port=8000
|
||||
```
|
||||
|
||||
### Routers
|
||||
|
||||
To update the configuration of the Router automatically attached to the container,
|
||||
add labels starting with `traefik.http.routers.<name-of-your-choice>.` and followed by the option you want to change.
|
||||
|
||||
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`example.com`)```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.rule=Host(`example.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
See [ruleSyntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.middlewares=auth,prefix,cb"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.tls.domains[0].main=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.tls.domains[0].sans=test.example.org,dev.example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.tls.options=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.accesslogs=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.metrics=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.tracing=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.priority=42"
|
||||
```
|
||||
|
||||
### Services
|
||||
|
||||
To update the configuration of the Service automatically attached to the container,
|
||||
add labels starting with `traefik.http.services.<name-of-your-choice>.`, followed by the option you want to change.
|
||||
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.passhostheader=false`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
Useful when the container exposes multiples ports.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.server.scheme=http"
|
||||
```
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.serverstransport=foobar@file"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.passhostheader=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.hostname=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.interval=10s"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.method`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.status=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.port=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10s"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can declare pieces of middleware using labels starting with `traefik.http.middlewares.<name-of-your-choice>.`,
|
||||
followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`redirectscheme`](../http/middlewares/redirectscheme.md) named `my-redirect`,
|
||||
you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme=https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
# Declaring a middleware
|
||||
- traefik.http.middlewares.my-redirect.redirectscheme.scheme=https
|
||||
# Referencing a middleware
|
||||
- traefik.http.routers.my-container.middlewares=my-redirect
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers and/or Services using labels.
|
||||
|
||||
??? example "Declaring TCP Routers with one Service"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- "traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)"
|
||||
- "traefik.tcp.routers.my-router.tls=true"
|
||||
- "traefik.tcp.services.my-service.loadbalancer.server.port=4123"
|
||||
```
|
||||
|
||||
!!! warning "TCP and HTTP"
|
||||
|
||||
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||
You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../tcp/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.rule=HostSNI(`example.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls.domains[0].main=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.example.org,dev.example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls.options=mysoptions"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
See [TLS](../tcp/tls.md#passthrough) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.tls.passthrough=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../tcp/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.routers.mytcprouter.priority=42"
|
||||
```
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.services.mytcpservice.loadbalancer.server.port=423"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
|
||||
|
||||
Determines whether to use TLS when dialing with the backend.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.services.mytcpservice.loadbalancer.server.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version=1"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.tcp.services.mytcpservice.loadbalancer.serverstransport=foobar@file"
|
||||
```
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.tcp.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.tcp.middlewares.test-inflightconn.amount=10
|
||||
# Referencing a middleware
|
||||
traefik.tcp.routers.my-service.middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using labels.
|
||||
|
||||
??? example "Declaring UDP Routers with one Service"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- "traefik.udp.routers.my-router.entrypoints=udp"
|
||||
- "traefik.udp.services.my-service.loadbalancer.server.port=4123"
|
||||
```
|
||||
|
||||
!!! warning "UDP and HTTP"
|
||||
|
||||
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
|
||||
You can declare both a UDP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.udp.routers.myudprouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../udp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
"traefik.udp.routers.myudprouter.service=myservice"
|
||||
```
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
"traefik.udp.services.myudpservice.loadbalancer.server.port=423"
|
||||
```
|
||||
|
||||
### Specific Provider Options
|
||||
|
||||
#### `traefik.enable`
|
||||
|
||||
```yaml
|
||||
- "traefik.enable=true"
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the container by setting `traefik.enable` to true or false.
|
||||
|
||||
This option overrides the value of `exposedByDefault`.
|
||||
|
||||
#### `traefik.docker.network`
|
||||
|
||||
```yaml
|
||||
- "traefik.docker.network=mynetwork"
|
||||
```
|
||||
|
||||
Overrides the default docker network to use for connections to the container.
|
||||
|
||||
If a container is linked to several networks, be sure to set the proper network name (you can check this with `docker inspect <container_id>`),
|
||||
otherwise it will randomly pick one (depending on how docker is returning them).
|
||||
|
||||
!!! warning
|
||||
When deploying a stack from a compose file `stack`, the networks defined are prefixed with `stack`.
|
@ -0,0 +1,572 @@
|
||||
---
|
||||
title: "Traefik ECS Documentation"
|
||||
description: "AWS ECS is a provider for routing and load balancing in Traefik Proxy. Read the technical documentation to get started."
|
||||
---
|
||||
|
||||
# Traefik & ECS
|
||||
|
||||
One of the best feature of Traefik is to delegate the routing configuration to the application level.
|
||||
With ECS, Traefik can leverage labels attached to a container to generate routing rules.
|
||||
|
||||
!!! warning "Labels & sensitive data"
|
||||
|
||||
We recommend to *not* use labels to store sensitive data (certificates, credentials, etc).
|
||||
Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc).
|
||||
|
||||
## Routing Configurationred
|
||||
|
||||
!!! info "labels"
|
||||
|
||||
Labels are case-insensitive.
|
||||
|
||||
!!! tip "TLS Default Generated Certificates"
|
||||
|
||||
To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page.
|
||||
|
||||
### General
|
||||
|
||||
Traefik creates, for each elastic service, a corresponding [service](../http/load-balancing/service.md) and [router](../http/router/rules-and-priority.md).
|
||||
|
||||
The Service automatically gets a server per elastic container, and the router gets a default rule attached to it, based on the service name.
|
||||
|
||||
### Routers
|
||||
|
||||
To update the configuration of the Router automatically attached to the service, add labels starting with `traefik.routers.{name-of-your-choice}.` and followed by the option you want to change.
|
||||
|
||||
For example, to change the rule, you could add the label ```traefik.http.routers.my-service.rule=Host(`example.com`)```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.rule=Host(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
See [ruleSyntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.entrypoints=web,websecure
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.middlewares=auth,prefix,cb
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.options=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.accesslogs=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.metrics=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.tracing=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.priority=42
|
||||
```
|
||||
|
||||
### Services
|
||||
|
||||
To update the configuration of the Service automatically attached to the service,
|
||||
add labels starting with `traefik.http.services.{name-of-your-choice}.`, followed by the option you want to change.
|
||||
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
Useful when the service exposes multiples ports.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.port=8080
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.scheme=http
|
||||
```
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.passhostheader=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.hostname=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.interval=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.method`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.port=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
|
||||
|
||||
```yaml
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
|
||||
`FlushInterval` specifies the flush interval to flush to the client while copying the response body.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can declare pieces of middleware using labels starting with `traefik.http.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`redirectscheme`](../http/middlewares/redirectscheme.md) named `my-redirect`, you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme: https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.http.middlewares.my-redirect.redirectscheme.scheme=https
|
||||
# Referencing a middleware
|
||||
traefik.http.routers.my-service.middlewares=my-redirect
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers and/or Services using labels.
|
||||
|
||||
??? example "Declaring TCP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)
|
||||
traefik.tcp.routers.my-router.tls=true
|
||||
traefik.tcp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "TCP and HTTP"
|
||||
|
||||
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||
You can declare both a TCP Router/Service and an HTTP Router/Service for the same elastic service (but you have to do so manually).
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.rule=HostSNI(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.options=mysoptions
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
See [Passthrough](../tcp/tls.md#passthrough) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.passthrough=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../tcp/router/rules-and-priority.md#priority) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.priority=42
|
||||
```
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
|
||||
|
||||
Determines whether to use TLS when dialing with the backend.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.weight`"
|
||||
|
||||
Overrides the default weight.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.weight=42
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version=1
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.<service_name>.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using tags.
|
||||
|
||||
??? example "Declaring UDP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.my-router.entrypoints=udp
|
||||
traefik.udp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "UDP and HTTP"
|
||||
|
||||
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
|
||||
You can declare both a UDP Router/Service and an HTTP Router/Service for the same elastic service (but you have to do so manually).
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.tcp.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.tcp.middlewares.test-inflightconn.amount=10
|
||||
# Referencing a middleware
|
||||
traefik.tcp.routers.my-service.middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../udp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.service=myservice
|
||||
```
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.udp.services.myudpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
### Specific Provider Options
|
||||
|
||||
#### `traefik.enable`
|
||||
|
||||
```yaml
|
||||
traefik.enable=true
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the ECS service by setting `traefik.enable` to true or false.
|
||||
|
||||
This option overrides the value of `exposedByDefault`.
|
@ -0,0 +1,609 @@
|
||||
---
|
||||
title: "Traefik Routing Configuration with KV stores"
|
||||
description: "Read the technical documentation to learn the Traefik Routing Configuration with KV stores."
|
||||
---
|
||||
|
||||
# Traefik & KV Stores
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "Keys"
|
||||
|
||||
Keys are case-insensitive.
|
||||
|
||||
### Routers
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------|----------------------------|
|
||||
| `traefik/http/routers/myrouter/rule` | ```Host(`example.com`)``` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/ruleSyntax`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------|----------------------------|
|
||||
| `traefik/http/routers/myrouter/ruleSyntax` | `v3` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------|-------------|
|
||||
| `traefik/http/routers/myrouter/entrypoints/0` | `web` |
|
||||
| `traefik/http/routers/myrouter/entrypoints/1` | `websecure` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------|-------------|
|
||||
| `traefik/http/routers/myrouter/middlewares/0` | `auth` |
|
||||
| `traefik/http/routers/myrouter/middlewares/1` | `prefix` |
|
||||
| `traefik/http/routers/myrouter/middlewares/2` | `cb` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------|-------------|
|
||||
| `traefik/http/routers/myrouter/service` | `myservice` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------|--------|
|
||||
| `traefik/http/routers/myrouter/tls` | `true` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/tls/certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------|--------------|
|
||||
| `traefik/http/routers/myrouter/tls/certresolver` | `myresolver` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/tls/domains/<n>/main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------|---------------|
|
||||
| `traefik/http/routers/myrouter/tls/domains/0/main` | `example.org` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/tls/domains/<n>/sans/<n>`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------|--------------------|
|
||||
| `traefik/http/routers/myrouter/tls/domains/0/sans/0` | `test.example.org` |
|
||||
| `traefik/http/routers/myrouter/tls/domains/0/sans/1` | `dev.example.org` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/tls/options`"
|
||||
|
||||
See [TLS](../http/tls/overview.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------|----------|
|
||||
| `traefik/http/routers/myrouter/tls/options` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/observability/accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------|--------|
|
||||
| `traefik/http/routers/myrouter/observability/accesslogs` | `true` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/observability/metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------|--------|
|
||||
| `traefik/http/routers/myrouter/observability/metrics` | `true` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/observability/tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------|--------|
|
||||
| `traefik/http/routers/myrouter/observability/tracing` | `true` |
|
||||
|
||||
??? info "`traefik/http/routers/<router_name>/priority`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------|-------|
|
||||
| `traefik/http/routers/myrouter/priority` | `42` |
|
||||
|
||||
### Services
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/servers/<n>/url`"
|
||||
|
||||
See [servers](../http/load-balancing/service.md#servers) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|-----------------------------------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/url` | `http://<ip-server-1>:<port-server-1>/` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/servers/<n>/preservePath`"
|
||||
|
||||
See [servers](../http/load-balancing/service.md#servers) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|-----------------------------------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/preservePath` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/servers/<n>/weight`"
|
||||
|
||||
See [servers](../http/load-balancing/service.md#servers) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|-----------------------------------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/weight` | `1` |
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|---------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/serverstransport` | `foobar@file` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/passhostheader`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/passhostheader` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/headers/<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/headers/X-Foo` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|---------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/hostname` | `example.org` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/interval` | `10` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/path` | `/foo` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/method`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/method` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/status` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/port` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/scheme` | `http` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/healthcheck/timeout` | `10` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/httponly`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/httponly` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/path`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|-----------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/path` | `/foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/secure`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/secure` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/samesite`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/samesite` | `none` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/maxage`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/maxage` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/responseforwarding/flushinterval`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/myservice/loadbalancer/responseforwarding/flushinterval` | `10` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/mirroring/service`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------|----------|
|
||||
| `traefik/http/services/<service_name>/mirroring/service` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/mirroring/mirrors/<n>/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/<service_name>/mirroring/mirrors/<n>/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/mirroring/mirrors/<n>/percent`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/mirroring/mirrors/<n>/percent` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/services/<n>/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/<service_name>/weighted/services/<n>/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/services/<n>/weight`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/weighted/services/<n>/weight` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------|----------|
|
||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/secure`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/secure` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/samesite`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/samesite` | `none` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/httpOnly`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/httpOnly` | `true` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/maxage`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/weighted/sticky/cookie/maxage` | `42` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/failover/fallback`"
|
||||
|
||||
See [Failover](../http/load-balancing/service.md#failover) for more information
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/failover/fallback` | `backup` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/failover/healthcheck`"
|
||||
|
||||
See [Failover](../http/load-balancing/service.md#failover) for more information
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/failover/healthcheck` | `{}` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/failover/service`"
|
||||
|
||||
See [Failover](../http/load-balancing/service.md#failover) for more information
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------------------------|-------|
|
||||
| `traefik/http/services/<service_name>/failover/service` | `main` |
|
||||
|
||||
### Middleware
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers and/or Services using KV.
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------|-------|
|
||||
| `traefik/tcp/routers/mytcprouter/entrypoints/0` | `ep1` |
|
||||
| `traefik/tcp/routers/mytcprouter/entrypoints/1` | `ep2` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/rule`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------|------------------------------|
|
||||
| `traefik/tcp/routers/my-router/rule` | ```HostSNI(`example.com`)``` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------|-------------|
|
||||
| `traefik/tcp/routers/mytcprouter/service` | `myservice` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------|--------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls` | `true` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls/certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|----------------------------------------------------|--------------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls/certresolver` | `myresolver` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls/domains/<n>/main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------|---------------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls/domains/0/main` | `example.org` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls/domains/<n>/sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------|--------------------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls/domains/0/sans/0` | `test.example.org` |
|
||||
| `traefik/tcp/routers/mytcprouter/tls/domains/0/sans/1` | `dev.example.org` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls/options`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------|----------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls/options` | `foobar` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/tls/passthrough`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------|--------|
|
||||
| `traefik/tcp/routers/mytcprouter/tls/passthrough` | `true` |
|
||||
|
||||
??? info "`traefik/tcp/routers/<router_name>/priority`"
|
||||
|
||||
See [priority](../tcp/router/rules-and-priority.md#priority) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------|-------|
|
||||
| `traefik/tcp/routers/mytcprouter/priority` | `42` |
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/loadbalancer/servers/<n>/address`"
|
||||
|
||||
See [servers](../tcp/service.md#servers-load-balancer) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------|------------------|
|
||||
| `traefik/tcp/services/mytcpservice/loadbalancer/servers/0/address` | `xx.xx.xx.xx:xx` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/loadbalancer/servers/<n>/tls`"
|
||||
|
||||
See [servers](../tcp/service.md#servers-load-balancer) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------|------------------|
|
||||
| `traefik/tcp/services/mytcpservice/loadbalancer/servers/0/tls` | `true` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/loadbalancer/proxyprotocol/version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------------|-------|
|
||||
| `traefik/tcp/services/mytcpservice/loadbalancer/proxyprotocol/version` | `1` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/loadbalancer/serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|---------------|
|
||||
| `traefik/tcp/services/myservice/loadbalancer/serverstransport` | `foobar@file` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/weighted/services/<n>/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------|----------|
|
||||
| `traefik/tcp/services/<service_name>/weighted/services/0/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/weighted/services/<n>/weight`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/tcp/services/<service_name>/weighted/services/0/weight` | `42` |
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik/tcp/middlewares/{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik/tcp/middlewares/test-inflightconn/inflightconn/amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```bash
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik/tcp/middlewares/test-inflightconn/amount=10
|
||||
# Referencing a middleware
|
||||
traefik/tcp/routers.my-service/middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using KV.
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik/udp/routers/<router-name>/entrypoints/<n>`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/udp/routers/myudprouter/entrypoints/0` | `foobar` |
|
||||
|
||||
??? info "`traefik/udp/routers/<router-name>/service`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/udp/routers/myudprouter/service` | `foobar` |
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik/udp/services/loadBalancer/servers/<n>/address`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/udp/services/loadBalancer/servers/<n>/address` | `foobar` |
|
||||
|
||||
??? info "`traefik/udp/services/weighted/services/<n>/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/udp/services/weighted/services/0/name` | `foobar` |
|
||||
|
||||
??? info "`traefik/udp/services/weighted/services/<n>/name`"
|
||||
|
||||
| Key (Path) | Value |
|
||||
|------------------------------------------------------------------|-------|
|
||||
| `traefik/udp/services/weighted/servers/0/weight` | `42` |
|
||||
|
||||
## TLS
|
||||
|
||||
### TLS Options
|
||||
|
||||
With the KV provider, you configure some parameters of the TLS connection using the `tls/options` key. For example, you can define a basic setup like this:
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------------------|------------------|
|
||||
| `traefik/tls/options/Options0/alpnProtocols/0` | `foobar` |
|
||||
| `traefik/tls/options/Options0/cipherSuites/0` | `foobar` |
|
||||
| `traefik/tls/options/Options0/clientAuth/caFiles/0` | `foobar` |
|
||||
|
||||
For more information on the available TLS options that can be configured, please refer to the [TLS Options](../http/tls/tls-options.md) page.
|
||||
|
||||
### TLS Default Generated Certificates
|
||||
|
||||
You can configure Traefik to use an ACME provider (like Let's Encrypt) to generate the default certificate. The configuration to resolve the default certificate should be defined in a TLS store:
|
||||
|
||||
| Key (Path) | Value |
|
||||
|---------------------------------------------------------------------------------|----------------|
|
||||
| `traefik/tls/stores/Store0/defaultGeneratedCert/domain/main` | `foobar` |
|
||||
| `traefik/tls/stores/Store0/defaultGeneratedCert/domain/sans/0` | `foobar` |
|
||||
| `traefik/tls/stores/Store0/defaultGeneratedCert/domain/sans/1` | `foobar` |
|
||||
| `traefik/tls/stores/Store0/defaultGeneratedCert/resolver` | `foobar` |
|
@ -0,0 +1,574 @@
|
||||
---
|
||||
title: "Traefik Nomad Service Discovery Routing"
|
||||
description: "Learn how to use Nomad Service Discovery as a provider for routing configurations in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Traefik and Nomad Service Discovery
|
||||
|
||||
One of the best feature of Traefik is to delegate the routing configuration to the application level.
|
||||
With Nomad, Traefik can leverage tags attached to a service to generate routing rules.
|
||||
|
||||
!!! warning "Tags & sensitive data"
|
||||
|
||||
We recommend to *not* use tags to store sensitive data (certificates, credentials, etc).
|
||||
Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc).
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "Tags"
|
||||
|
||||
Tags are case-insensitive.
|
||||
|
||||
!!! tip "TLS Default Generated Certificates"
|
||||
|
||||
To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page.
|
||||
|
||||
### General
|
||||
|
||||
Traefik creates, for each Nomad service, a corresponding Traefik [service](../http/load-balancing/service.md) and [router](../http/router/rules-and-priority.md).
|
||||
|
||||
The Traefik service automatically gets a server per instance in this Nomad service, and the router gets a default rule attached to it, based on the Nomad service name.
|
||||
|
||||
### Routers
|
||||
|
||||
To update the configuration of the Router automatically attached to the service, add tags starting with `traefik.routers.{name-of-your-choice}.` and followed by the option you want to change.
|
||||
|
||||
For example, to change the rule, you could add the tag ```traefik.http.routers.my-service.rule=Host(`example.com`)```.
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.rule=Host(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
See [ruleSyntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.entrypoints=web,websecure
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.middlewares=auth,prefix,cb
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.tls.options=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.priority=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.accesslogs=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.metrics=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.tracing=true"
|
||||
```
|
||||
|
||||
### Services
|
||||
|
||||
To update the configuration of the Service automatically attached to the service,
|
||||
add tags starting with `traefik.http.services.{name-of-your-choice}.`, followed by the option you want to change.
|
||||
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false`.
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
Useful when the service exposes multiples ports.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.port=8080
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.scheme=http
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.weight`"
|
||||
|
||||
Overrides the default weight.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.weight=42
|
||||
```
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.passhostheader=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.hostname=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.interval=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.port=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.maxage`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.http.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`redirectscheme`](../http/middlewares/redirectscheme.md) named `my-redirect`, you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme: https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.http.middlewares.my-redirect.redirectscheme.scheme=https
|
||||
# Referencing a middleware
|
||||
traefik.http.routers.my-service.middlewares=my-redirect
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers and/or Services using tags.
|
||||
|
||||
??? example "Declaring TCP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)
|
||||
traefik.tcp.routers.my-router.tls=true
|
||||
traefik.tcp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "TCP and HTTP"
|
||||
|
||||
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||
You can declare both a TCP Router/Service and an HTTP Router/Service for the same Nomad service (but you have to do so manually).
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../tcp/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.rule=HostSNI(`example.com`)
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../tcp/router/rules-and-priority.md#priority) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.myrouter.priority=42
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.service=myservice
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].main=example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.example.org,dev.example.org
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
See [TLS](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.options=myoptions
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
See [Passthrough](../tcp/tls.md#passthrough) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.tls.passthrough=true
|
||||
```
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
|
||||
|
||||
Determines whether to use TLS when dialing with the backend.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.server.tls=true
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version=1
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.services.myservice.loadbalancer.serverstransport=foobar@file
|
||||
```
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.tcp.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.tcp.middlewares.test-inflightconn.amount=10
|
||||
# Referencing a middleware
|
||||
traefik.tcp.routers.my-service.middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using tags.
|
||||
|
||||
??? example "Declaring UDP Routers and Services"
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.my-router.entrypoints=udp
|
||||
traefik.udp.services.my-service.loadbalancer.server.port=4123
|
||||
```
|
||||
|
||||
!!! warning "UDP and HTTP"
|
||||
|
||||
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
|
||||
You can declare both a UDP Router/Service and an HTTP Router/Service for the same Nomad service (but you have to do so manually).
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.entrypoints=ep1,ep2
|
||||
```
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../udp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.udp.routers.myudprouter.service=myservice
|
||||
```
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
traefik.udp.services.myudpservice.loadbalancer.server.port=423
|
||||
```
|
||||
|
||||
### Specific Provider Options
|
||||
|
||||
#### `traefik.enable`
|
||||
|
||||
```yaml
|
||||
traefik.enable=true
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the service by setting `traefik.enable` to true or false.
|
||||
|
||||
This option overrides the value of `exposedByDefault`.
|
||||
|
||||
#### `traefik.nomad.canary`
|
||||
|
||||
```yaml
|
||||
traefik.nomad.canary=true
|
||||
```
|
||||
|
||||
When Nomad orchestrator is a provider (of service registration) for Traefik,
|
||||
one might have the need to distinguish within Traefik between a [Canary](https://learn.hashicorp.com/tutorials/nomad/job-blue-green-and-canary-deployments#deploy-with-canaries) instance of a service, or a production one.
|
||||
For example if one does not want them to be part of the same load-balancer.
|
||||
|
||||
Therefore, this option, which is meant to be provided as one of the values of the `canary_tags` field in the Nomad [service stanza](https://www.nomadproject.io/docs/job-specification/service#canary_tags),
|
||||
allows Traefik to identify that the associated instance is a canary one.
|
||||
|
||||
#### Port Lookup
|
||||
|
||||
Traefik is capable of detecting the port to use, by following the default Nomad Service Discovery flow.
|
||||
That means, if you just expose lets say port `:1337` on the Nomad job, traefik will pick up this port and use it.
|
@ -0,0 +1,732 @@
|
||||
---
|
||||
title: "Traefik Docker Swarm Routing Documentation"
|
||||
description: "This guide will teach you how to attach labels to your containers, to route traffic and load balance with Traefik and Docker Swarm."
|
||||
---
|
||||
|
||||
# Traefik & Docker Swarm
|
||||
|
||||
One of the best feature of Traefik is to delegate the routing configuration to the application level.
|
||||
With Docker Swarm, Traefik can leverage labels attached to a service to generate routing rules.
|
||||
|
||||
!!! warning "Labels & sensitive data"
|
||||
|
||||
We recommend to *not* use labels to store sensitive data (certificates, credentials, etc).
|
||||
Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc).
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
??? example "Configuring Docker Swarm & Deploying / Exposing one Service"
|
||||
|
||||
Enabling the docker provider (Swarm Mode)
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
providers:
|
||||
swarm:
|
||||
# swarm classic (1.12-)
|
||||
# endpoint: "tcp://127.0.0.1:2375"
|
||||
# docker swarm mode (1.12+)
|
||||
endpoint: "tcp://127.0.0.1:2377"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.swarm]
|
||||
# swarm classic (1.12-)
|
||||
# endpoint = "tcp://127.0.0.1:2375"
|
||||
# docker swarm mode (1.12+)
|
||||
endpoint = "tcp://127.0.0.1:2377"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# swarm classic (1.12-)
|
||||
# --providers.swarm.endpoint=tcp://127.0.0.1:2375
|
||||
# docker swarm mode (1.12+)
|
||||
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
||||
```
|
||||
|
||||
Attach labels to services (not containers) while in Swarm mode (in your Docker compose file).
|
||||
When there is only one service, and the router does not specify a service,
|
||||
then that service is automatically assigned to the router.
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.my-container.rule=Host(`example.com`)
|
||||
- traefik.http.services.my-container-service.loadbalancer.server.port=8080
|
||||
```
|
||||
|
||||
!!! important "Labels in Docker Swarm Mode"
|
||||
While in Swarm Mode, Traefik uses labels found on services, not on individual containers.
|
||||
Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service.
|
||||
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)).
|
||||
|
||||
??? example "Specify a Custom Port for the Container"
|
||||
|
||||
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.my-container.rule=Host(`example.com`)
|
||||
- traefik.http.routers.my-container.service=my-service"
|
||||
# Tell Traefik to use the port 12345 to connect to `my-container`
|
||||
- traefik.http.services.my-service.loadbalancer.server.port=12345
|
||||
```
|
||||
|
||||
!!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`"
|
||||
By default, Traefik uses the lowest exposed port of a container as detailed in
|
||||
[Port Detection](../../install-configuration/providers/swarm.md#port-detection) of the Swarm provider.
|
||||
|
||||
Setting the label `traefik.http.services.xxx.loadbalancer.server.port`
|
||||
overrides this behavior.
|
||||
|
||||
??? example "Specifying more than one router and service per container"
|
||||
|
||||
Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router.
|
||||
|
||||
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.www-router.rule=Host(`example-a.com`)
|
||||
- traefik.http.routers.www-router.service=www-service
|
||||
- traefik.http.services.www-service.loadbalancer.server.port=8000
|
||||
- traefik.http.routers.admin-router.rule=Host(`example-b.com`)
|
||||
- traefik.http.routers.admin-router.service=admin-service
|
||||
- traefik.http.services.admin-service.loadbalancer.server.port=9000
|
||||
```
|
||||
|
||||
## Routing Configuration
|
||||
|
||||
!!! info "Labels"
|
||||
|
||||
Labels are case-insensitive.
|
||||
|
||||
!!! tip "TLS Default Generated Certificates"
|
||||
|
||||
To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page.
|
||||
|
||||
### General
|
||||
|
||||
Traefik creates, for each container, a corresponding [service](../http/load-balancing/service.md) and [router](../http/router/rules-and-priority.md).
|
||||
|
||||
The Service automatically gets a server per instance of the container,
|
||||
and the router automatically gets a rule defined by `defaultRule` (if no rule for it was defined in labels).
|
||||
|
||||
#### Service definition
|
||||
|
||||
--8<-- "content/routing/providers/service-by-label.md"
|
||||
|
||||
??? example "Automatic service assignment with labels"
|
||||
|
||||
With labels in a compose file
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
||||
# service myservice gets automatically assigned to router myproxy
|
||||
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
??? example "Automatic service creation and assignment with labels"
|
||||
|
||||
With labels in a compose file
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# no service specified or defined and yet one gets automatically created
|
||||
# and assigned to router myproxy.
|
||||
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
||||
```
|
||||
|
||||
### Routers
|
||||
|
||||
To update the configuration of the Router automatically attached to the container,
|
||||
add labels starting with `traefik.http.routers.<name-of-your-choice>.` and followed by the option you want to change.
|
||||
|
||||
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`example.com`)```.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../http/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.rule=Host(`example.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
See [ruleSyntax](../http/router/rules-and-priority.md#rulesyntax) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.http.routers.myrouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.middlewares`"
|
||||
|
||||
See [middlewares overview](../http/middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.middlewares=auth,prefix,cb"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.service`"
|
||||
|
||||
See [service](../http/load-balancing/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls`"
|
||||
|
||||
See [tls](../http/tls/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.domains[0].main=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.domains[0].sans=test.example.org,dev.example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.tls.options`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.tls.options=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.accesslogs`"
|
||||
|
||||
The accessLogs option controls whether the router will produce access-logs.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.accesslogs=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.metrics`"
|
||||
|
||||
The metrics option controls whether the router will produce metrics.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.metrics=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.observability.tracing`"
|
||||
|
||||
The tracing option controls whether the router will produce traces.
|
||||
|
||||
```yaml
|
||||
"traefik.http.routers.myrouter.observability.tracing=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../http/router/rules-and-priority.md#priority-calculation) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.myrouter.priority=42"
|
||||
```
|
||||
|
||||
### Services
|
||||
|
||||
To update the configuration of the Service automatically attached to the container,
|
||||
add labels starting with `traefik.http.services.<name-of-your-choice>.`, followed by the option you want to change.
|
||||
|
||||
For example, to change the `passHostHeader` behavior,
|
||||
you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.passhostheader=false`.
|
||||
|
||||
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port.
|
||||
Useful when the container exposes multiples ports.
|
||||
|
||||
Mandatory for Docker Swarm (see the section ["Port Detection with Docker Swarm"](../../install-configuration/providers/swarm.md#port-detection)).
|
||||
{: #port }
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.server.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.server.weight`"
|
||||
|
||||
Overrides the default weight.
|
||||
|
||||
```yaml
|
||||
traefik.http.services.myservice.loadbalancer.server.weight=42
|
||||
```
|
||||
|
||||
??? 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.
|
||||
See [serverstransport](../http/load-balancing/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.passhostheader=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.hostname=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.interval=10s"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.method`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.status=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.port=42"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.scheme=http"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10s"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
|
||||
|
||||
See [health check](../http/load-balancing/service.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
|
||||
|
||||
See [response forwarding](../http/load-balancing/service.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can declare pieces of middleware using labels starting with `traefik.http.middlewares.<name-of-your-choice>.`,
|
||||
followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`redirectscheme`](../http/middlewares/redirectscheme.md) named `my-redirect`,
|
||||
you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme=https`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../http/middlewares/overview.md).
|
||||
|
||||
!!! warning "The character `@` is not authorized in the middleware name."
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
deploy:
|
||||
labels:
|
||||
# Declaring a middleware
|
||||
- traefik.http.middlewares.my-redirect.redirectscheme.scheme=https
|
||||
# Referencing a middleware
|
||||
- traefik.http.routers.my-container.middlewares=my-redirect
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### TCP
|
||||
|
||||
You can declare TCP Routers and/or Services using labels.
|
||||
|
||||
??? example "Declaring TCP Routers and Services"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
deploy:
|
||||
labels:
|
||||
- "traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)"
|
||||
- "traefik.tcp.routers.my-router.tls=true"
|
||||
- "traefik.tcp.services.my-service.loadbalancer.server.port=4123"
|
||||
```
|
||||
|
||||
!!! warning "TCP and HTTP"
|
||||
|
||||
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||
You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
|
||||
|
||||
#### TCP Routers
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.rule`"
|
||||
|
||||
See [rule](../tcp/router/rules-and-priority.md#rules) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.rule=HostSNI(`example.com`)"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.ruleSyntax`"
|
||||
|
||||
configure the rule syntax to be used for parsing the rule on a per-router basis.
|
||||
|
||||
```yaml
|
||||
traefik.tcp.routers.mytcprouter.ruleSyntax=v3
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../tcp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.service=myservice"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
|
||||
|
||||
See [certResolver](../tcp/tls.md#configuration-options) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.domains[0].main=example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.example.org,dev.example.org"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
|
||||
|
||||
See [TLS](../tcp/tls.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.options=mysoptions"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
|
||||
|
||||
See [Passthrough](../tcp/tls.md#passthrough) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.mytcprouter.tls.passthrough=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.routers.<router_name>.priority`"
|
||||
|
||||
See [priority](../tcp/router/rules-and-priority.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.routers.myrouter.priority=42"
|
||||
```
|
||||
|
||||
#### TCP Services
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.mytcpservice.loadbalancer.server.port=423"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
|
||||
|
||||
Determines whether to use TLS when dialing with the backend.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.mytcpservice.loadbalancer.server.tls=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
|
||||
|
||||
See [PROXY protocol](../tcp/service.md#proxy-protocol) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version=1"
|
||||
```
|
||||
|
||||
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
|
||||
|
||||
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
|
||||
See [serverstransport](../tcp/serverstransport.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.tcp.services.<service_name>.loadbalancer.serverstransport=foobar@file"
|
||||
```
|
||||
|
||||
#### TCP Middleware
|
||||
|
||||
You can declare pieces of middleware using tags starting with `traefik.tcp.middlewares.{name-of-your-choice}.`, followed by the middleware type/options.
|
||||
|
||||
For example, to declare a middleware [`InFlightConn`](../tcp/middlewares/inflightconn.md) named `test-inflightconn`, you'd write `traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10`.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../tcp/middlewares/overview.md).
|
||||
|
||||
??? example "Declaring and Referencing a Middleware"
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
# Declaring a middleware
|
||||
traefik.tcp.middlewares.test-inflightconn.amount=10
|
||||
# Referencing a middleware
|
||||
traefik.tcp.routers.my-service.middlewares=test-inflightconn
|
||||
```
|
||||
|
||||
!!! warning "Conflicts in Declaration"
|
||||
|
||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||
|
||||
### UDP
|
||||
|
||||
You can declare UDP Routers and/or Services using labels.
|
||||
|
||||
??? example "Declaring UDP Routers and Services"
|
||||
|
||||
```yaml
|
||||
services:
|
||||
my-container:
|
||||
# ...
|
||||
deploy:
|
||||
labels:
|
||||
- "traefik.udp.routers.my-router.entrypoints=udp"
|
||||
- "traefik.udp.services.my-service.loadbalancer.server.port=4123"
|
||||
```
|
||||
|
||||
!!! warning "UDP and HTTP"
|
||||
|
||||
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
|
||||
You can declare both a UDP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
|
||||
|
||||
#### UDP Routers
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
|
||||
|
||||
See [entry points](../../install-configuration/entrypoints.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.udp.routers.myudprouter.entrypoints=ep1,ep2"
|
||||
```
|
||||
|
||||
??? info "`traefik.udp.routers.<router_name>.service`"
|
||||
|
||||
See [service](../udp/service.md) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.udp.routers.myudprouter.service=myservice"
|
||||
```
|
||||
|
||||
#### UDP Services
|
||||
|
||||
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
|
||||
|
||||
Registers a port of the application.
|
||||
|
||||
```yaml
|
||||
- "traefik.udp.services.myudpservice.loadbalancer.server.port=423"
|
||||
```
|
||||
|
||||
### Specific Provider Options
|
||||
|
||||
#### `traefik.enable`
|
||||
|
||||
```yaml
|
||||
- "traefik.enable=true"
|
||||
```
|
||||
|
||||
You can tell Traefik to consider (or not) the container by setting `traefik.enable` to true or false.
|
||||
|
||||
This option overrides the value of `exposedByDefault`.
|
||||
|
||||
#### `traefik.swarm.network`
|
||||
|
||||
```yaml
|
||||
- "traefik.swarm.network=mynetwork"
|
||||
```
|
||||
|
||||
Overrides the default docker network to use for connections to the container.
|
||||
|
||||
If a container is linked to several networks, be sure to set the proper network name (you can check this with `docker inspect <container_id>`),
|
||||
otherwise it will randomly pick one (depending on how docker is returning them).
|
||||
|
||||
!!! warning
|
||||
When deploying a stack from a compose file `stack`, the networks defined are prefixed with `stack`.
|
||||
|
||||
#### `traefik.swarm.lbswarm`
|
||||
|
||||
```yaml
|
||||
- "traefik.docker.lbswarm=true"
|
||||
```
|
||||
|
||||
Enables Swarm's inbuilt load balancer (only relevant in Swarm Mode).
|
||||
|
||||
If you enable this option, Traefik will use the virtual IP provided by docker swarm instead of the containers IPs.
|
||||
Which means that Traefik will not perform any kind of load balancing and will delegate this task to swarm.
|
@ -0,0 +1,55 @@
|
||||
---
|
||||
title: 'Traefik InFlightConn Middleware - TCP'
|
||||
description: "Limiting the number of simultaneous connections."
|
||||
---
|
||||
|
||||
To proactively prevent Services from being overwhelmed with high load, the number of allowed simultaneous connections by IP can be limited with the `inFlightConn` TCP middleware.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
tcp:
|
||||
middlewares:
|
||||
test-inflightconn:
|
||||
inFlightConn:
|
||||
amount: 10
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.test-inflightconn.inFlightConn]
|
||||
amount = 10
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Limiting to 10 simultaneous connections
|
||||
{
|
||||
//..
|
||||
"Tags" : [
|
||||
"traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: test-inflightconn
|
||||
spec:
|
||||
inFlightConn:
|
||||
amount: 10
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|------------------|-------|
|
||||
| `amount` | The `amount` option defines the maximum amount of allowed simultaneous connections. <br /> The middleware closes the connection if there are already `amount` connections opened. | "" | Yes |
|
@ -0,0 +1,60 @@
|
||||
---
|
||||
title: "Traefik TCP Middlewares IPAllowList"
|
||||
description: "Learn how to use IPAllowList in TCP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
`iPAllowList` limits allowed requests based on the client IP.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# Accepts request from defined IP
|
||||
tcp:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# Accepts request from defined IP
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
# Accepts connections from defined IP
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
// Accepts request from defined IP
|
||||
{
|
||||
//...
|
||||
"Tags" : [
|
||||
"traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"s
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:------------|------------------|-------|
|
||||
| `sourceRange` | The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).| | Yes |
|
@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "Traefik Proxy TCP Middleware Overview"
|
||||
description: "Read the official Traefik Proxy documentation for an overview of the available TCP middleware."
|
||||
---
|
||||
# TCP Middleware Overview
|
||||
|
||||
Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your service (or before the answer from the services are sent to the clients).
|
||||
|
||||
There are several available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
|
||||
|
||||
Middlewares that use the same protocol can be combined into chains to fit every scenario.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
# As YAML Configuration File
|
||||
tcp:
|
||||
routers:
|
||||
router1:
|
||||
service: myService
|
||||
middlewares:
|
||||
- "foo-ip-allowlist"
|
||||
rule: "Host(`example.com`)"
|
||||
|
||||
middlewares:
|
||||
foo-ip-allowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
|
||||
services:
|
||||
service1:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "10.0.0.10:4000"
|
||||
- address: "10.0.0.11:4000"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
# As TOML Configuration File
|
||||
[tcp.routers]
|
||||
[tcp.routers.router1]
|
||||
service = "myService"
|
||||
middlewares = ["foo-ip-allowlist"]
|
||||
rule = "Host(`example.com`)"
|
||||
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.foo-ip-allowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
|
||||
[tcp.services]
|
||||
[tcp.services.service1]
|
||||
[tcp.services.service1.loadBalancer]
|
||||
[[tcp.services.service1.loadBalancer.servers]]
|
||||
address = "10.0.0.10:4000"
|
||||
[[tcp.services.service1.loadBalancer.servers]]
|
||||
address = "10.0.0.11:4000"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
# Create a middleware named `foo-ip-allowlist`
|
||||
- "traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-allowlist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@docker"
|
||||
```
|
||||
|
||||
```json tab="Consul Catalog"
|
||||
{
|
||||
//...
|
||||
"Tags" : [
|
||||
// Create a middleware named `foo-ip-allowlist`
|
||||
"traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7",
|
||||
// Apply the middleware named `foo-ip-allowlist` to the router named `router1`
|
||||
"traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@consulcatalog"
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: foo-ip-allowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourcerange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: ingressroute
|
||||
spec:
|
||||
# more fields...
|
||||
routes:
|
||||
# more fields...
|
||||
middlewares:
|
||||
- name: foo-ip-allowlist
|
||||
```
|
||||
|
||||
## Available TCP Middlewares
|
||||
|
||||
| Middleware | Purpose | Area |
|
||||
|-------------------------------------------|---------------------------------------------------|-----------------------------|
|
||||
| [InFlightConn](inflightconn.md) | Limits the number of simultaneous connections. | Security, Request lifecycle |
|
||||
| [IPAllowList](ipallowlist.md) | Limit the allowed client IPs. | Security, Request lifecycle |
|
@ -0,0 +1,201 @@
|
||||
---
|
||||
title: "Traefik TCP Routers Rules & Priority Documentation"
|
||||
description: "In Traefik Proxy, a router is in charge of connecting incoming requests to the Services that can handle them. Read the technical documentation."
|
||||
---
|
||||
|
||||
|
||||
## General
|
||||
|
||||
!!! note
|
||||
- The character @ is not authorized in the router name
|
||||
- If both HTTP routers and TCP routers listen to the same [EntryPoint](../../../install-configuration/entrypoints.md), the TCP routers will apply before the HTTP routers. If no matching route is found for the TCP routers, then the HTTP routers will take over.
|
||||
|
||||
## Rules
|
||||
|
||||
Rules are a set of matchers configured with values, that determine if a particular connection matches specific criteria. If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.
|
||||
|
||||
The table below lists all the available matchers:
|
||||
|
||||
| Rule | Description |
|
||||
|-------------------------------------------------------------|:-------------------------------------------------------------------------------------------------|
|
||||
| [```HostSNI(`domain`)```](#hostsni-and-hostsniregexp) | Checks if the connection's Server Name Indication is equal to `domain`.<br /> More information [here](#hostsni-and-hostsniregexp). |
|
||||
| [```HostSNIRegexp(`regexp`)```](#hostsni-and-hostsniregexp) | Checks if the connection's Server Name Indication matches `regexp`.<br />Use a [Go](https://golang.org/pkg/regexp/) flavored syntax.<br /> More information [here](#hostsni-and-hostsniregexp). |
|
||||
| [```ClientIP(`ip`)```](#clientip) | Checks if the connection's client IP correspond to `ip`. It accepts IPv4, IPv6 and CIDR formats.<br /> More information [here](#clientip). |
|
||||
| [```ALPN(`protocol`)```](#alpn) | Checks if the connection's ALPN protocol equals `protocol`.<br /> More information [here](#alpn). |
|
||||
|
||||
!!! tip "Backticks or Quotes?"
|
||||
|
||||
To set the value of a rule, use [backticks](https://en.wiktionary.org/wiki/backtick) ``` ` ``` or escaped double-quotes `\"`.
|
||||
|
||||
Single quotes `'` are not accepted since the values are [Go's String Literals](https://golang.org/ref/spec#String_literals).
|
||||
|
||||
### Expressing Complex Rules Using Operators and Parenthesis
|
||||
|
||||
The usual AND (`&&`) and OR (`||`) logical operators can be used, with the expected precedence rules,
|
||||
as well as parentheses.
|
||||
|
||||
One can invert a matcher by using the NOT (`!`) operator.
|
||||
|
||||
The following rule matches connections where:
|
||||
|
||||
- Either Server Name Indication is `example.com` OR,
|
||||
- Server Name Indication is `example.org` AND ALPN protocol is NOT `h2`
|
||||
|
||||
```yaml
|
||||
HostSNI(`example.com`) || (HostSNI(`example.org`) && !ALPN(`h2`))
|
||||
```
|
||||
|
||||
### HostSNI and HostSNIRegexp
|
||||
|
||||
`HostSNI` and `HostSNIRegexp` matchers allow to match connections targeted to a given domain.
|
||||
|
||||
These matchers do not support non-ASCII characters, use punycode encoded values ([rfc 3492](https://tools.ietf.org/html/rfc3492)) to match such domains.
|
||||
|
||||
!!! note "HostSNI & TLS"
|
||||
|
||||
It is important to note that the Server Name Indication is an extension of the TLS protocol.
|
||||
Hence, only TLS routers will be able to specify a domain name with that rule.
|
||||
However, there is one special use case for `HostSNI` with non-TLS routers:
|
||||
when one wants a non-TLS router that matches all (non-TLS) requests,
|
||||
one should use the specific ```HostSNI(`*`)``` syntax.
|
||||
|
||||
#### Examples
|
||||
|
||||
Match all connections:
|
||||
|
||||
```yaml tab="HostSNI"
|
||||
HostSNI(`*`)
|
||||
```
|
||||
|
||||
```yaml tab="HostSNIRegexp"
|
||||
HostSNIRegexp(`^.*$`)
|
||||
```
|
||||
|
||||
Match TCP connections sent to `example.com`:
|
||||
|
||||
```yaml
|
||||
HostSNI(`example.com`)
|
||||
```
|
||||
|
||||
Match TCP connections opened on any subdomain of `example.com`:
|
||||
|
||||
```yaml
|
||||
HostSNIRegexp(`^.+\.example\.com$`)
|
||||
```
|
||||
|
||||
### ClientIP
|
||||
|
||||
The `ClientIP` matcher allows matching connections opened by a client with the given IP.
|
||||
|
||||
#### Examples
|
||||
|
||||
Match connections opened by a given IP:
|
||||
|
||||
```yaml tab="IPv4"
|
||||
ClientIP(`10.76.105.11`)
|
||||
```
|
||||
|
||||
```yaml tab="IPv6"
|
||||
ClientIP(`::1`)
|
||||
```
|
||||
|
||||
Match connections coming from a given subnet:
|
||||
|
||||
```yaml tab="IPv4"
|
||||
ClientIP(`192.168.1.0/24`)
|
||||
```
|
||||
|
||||
```yaml tab="IPv6"
|
||||
ClientIP(`fe80::/10`)
|
||||
```
|
||||
|
||||
### ALPN
|
||||
|
||||
The `ALPN` matcher allows matching connections the given protocol.
|
||||
|
||||
It would be a security issue to let a user-defined router catch the response to
|
||||
an ACME TLS challenge previously initiated by Traefik.
|
||||
For this reason, the `ALPN` matcher is not allowed to match the `ACME-TLS/1`
|
||||
protocol, and Traefik returns an error if this is attempted.
|
||||
|
||||
#### Example
|
||||
|
||||
Match connections using the ALPN protocol `h2`:
|
||||
|
||||
```yaml
|
||||
ALPN(`h2`)
|
||||
```
|
||||
|
||||
## Priority Calculation
|
||||
|
||||
???+ info "How default priorities are computed"
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
routers:
|
||||
Router-1:
|
||||
rule: "ClientIP(`192.168.0.12`)"
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: service-1
|
||||
priority: 2
|
||||
Router-2:
|
||||
rule: "ClientIP(`192.168.0.0/24`)"
|
||||
entryPoints:
|
||||
- "web"
|
||||
priority: 1
|
||||
service: service-2
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tcp.routers]
|
||||
[tcp.routers.Router-1]
|
||||
rule = "ClientIP(`192.168.0.12`)"
|
||||
entryPoints = ["web"]
|
||||
service = "service-1"
|
||||
priority = 2
|
||||
[tcp.routers.Router-2]
|
||||
rule = "ClientIP(`192.168.0.0/24`)"
|
||||
entryPoints = ["web"]
|
||||
priority = 1
|
||||
service = "service-2
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.tcp.routers.Router-1.rule="ClientIP(`192.168.0.12`)"
|
||||
- "traefik.tcp.routers.Router-1.entryPoints=web"
|
||||
- "traefik.tcp.routers.Router-1.service=service-1"
|
||||
- "traefik.tcp.routers.Router-1.priority=2"
|
||||
- "traefik.tcp.routers.Router-2.rule="ClientIP(`192.168.0.0/24`)"
|
||||
- "traefik.tcp.routers.Router-2.entryPoints=web"
|
||||
- "traefik.tcp.routers.Router-2.service=service-2"
|
||||
- "traefik.tcp.routers.Router-2.priority=1"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.tcp.routers.Router-1.rule=ClientIP(`192.168.0.12`)",
|
||||
"traefik.tcp.routers.Router-1.entryPoints=web",
|
||||
"traefik.tcp.routers.Router-1.service=service-1",
|
||||
"traefik.tcp.routers.Router-1.priority=2",
|
||||
"traefik.tcp.routers.Router-2.rule=ClientIP(`192.168.0.0/24`)",
|
||||
"traefik.tcp.routers.Router-2.entryPoints=web",
|
||||
"traefik.tcp.routers.Router-2.service=service-2",
|
||||
"traefik.tcp.routers.Router-2.priority=1"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, the priority is configured so that `Router-1` will handle requests from `192.168.0.12`.
|
||||
|
||||
To avoid path overlap, routes are sorted, by default, in descending order using rules length.
|
||||
The priority is directly equal to the length of the rule, and so the longest length has the highest priority.
|
||||
A value of `0` for the priority is ignored: `priority: 0` means that the default rules length sorting is used.
|
||||
|
||||
Traefik reserves a range of priorities for its internal routers, the maximum user-defined router priority value is:
|
||||
|
||||
- `(MaxInt32 - 1000)` for 32-bit platforms,
|
||||
- `(MaxInt64 - 1000)` for 64-bit platforms.
|
@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "ServersTransport TCP"
|
||||
description: "The ServersTransport allows configuring the connection between Traefik and the TCP servers in Kubernetes."
|
||||
---
|
||||
|
||||
ServersTransport allows to configure the transport between Traefik and your TCP servers.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Declare the serversTransport:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
serversTransports:
|
||||
mytransport:
|
||||
dialTimeout: "30s"
|
||||
dialKeepAlive: "20s"
|
||||
terminationDelay: "200ms"
|
||||
tls:
|
||||
serverName: "example.com"
|
||||
certificates:
|
||||
- "/path/to/cert1.pem"
|
||||
- "/path/to/cert2.pem"
|
||||
insecureSkipVerify: true
|
||||
rootcas:
|
||||
- "/path/to/rootca.pem"
|
||||
peerCertURI: "spiffe://example.org/peer"
|
||||
spiffe:
|
||||
ids:
|
||||
- "spiffe://example.org/id1"
|
||||
- "spiffe://example.org/id2"
|
||||
trustDomain: "example.org"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tcp.serversTransports.mytransport]
|
||||
dialTimeout = "30s"
|
||||
dialKeepAlive = "20s"
|
||||
terminationDelay = "200ms"
|
||||
|
||||
[tcp.serversTransports.mytransport.tls]
|
||||
serverName = "example.com"
|
||||
certificates = ["/path/to/cert1.pem", "/path/to/cert2.pem"]
|
||||
insecureSkipVerify = true
|
||||
rootcas = ["/path/to/rootca.pem"]
|
||||
peerCertURI = "spiffe://example.org/peer"
|
||||
|
||||
[tcp.serversTransports.mytransport.spiffe]
|
||||
ids = ["spiffe://example.org/id1", "spiffe://example.org/id2"]
|
||||
trustDomain = "example.org"
|
||||
```
|
||||
|
||||
Attach the serversTransport to a service:
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
services:
|
||||
Service01:
|
||||
loadBalancer:
|
||||
serversTransport: mytransport
|
||||
```
|
||||
|
||||
```toml tab="Structured(TOML)"
|
||||
## Dynamic configuration
|
||||
[tcp.services]
|
||||
[tcp.services.Service01]
|
||||
[tcp.services.Service01.loadBalancer]
|
||||
serversTransport = "mytransport"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.tcp.services.Service01.loadBalancer.serversTransport=mytransport"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
// ...
|
||||
"Tags": [
|
||||
"traefik.tcp.services.Service01.loadBalancer.serversTransport=mytransport"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------|:----------------------------------------------------------|:---------------------|:---------|
|
||||
| `serverstransport.`<br />`dialTimeout` | Defines the timeout when dialing the backend TCP service. If zero, no timeout exists. | 30s | No |
|
||||
| `serverstransport.`<br />`dialKeepAlive` | Defines the interval between keep-alive probes for an active network connection. | 15s | No |
|
||||
| `serverstransport.`<br />`terminationDelay` | Sets the time limit for the proxy to fully terminate connections on both sides after initiating the termination sequence, with a negative value indicating no deadline. More Information [here](#terminationdelay) | 100ms | No |
|
||||
| `serverstransport.`<br />`tls` | Defines the TLS configuration. An empty `tls` section enables TLS. | | No |
|
||||
| `serverstransport.`<br />`tls`<br />`.serverName` | Configures the server name that will be used for SNI. | | No |
|
||||
| `serverstransport.`<br />`tls`<br />`.certificates` | Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. | | No |
|
||||
| `serverstransport.`<br />`tls`<br />`.insecureSkipVerify` | Controls whether the server's certificate chain and host name is verified. | false | No |
|
||||
| `serverstransport.`<br />`tls`<br />`.rootcas` | Defines the root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
|
||||
| `serverstransport.`<br />`tls.`<br />`peerCertURI` | Defines the URI used to match against SAN URIs during the server's certificate verification. | false | No |
|
||||
| `serverstransport.`<br />`spiffe`<br />`.ids` | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
|
||||
| `serverstransport.`<br />`spiffe`<br />`.trustDomain` | Allow SPIFFE trust domain. | "" | No |
|
||||
|
||||
!!! note "SPIFFE"
|
||||
|
||||
Please note that SPIFFE must be enabled in the [install configuration](../../install-configuration/tls/spiffe.md) (formerly known as static configuration) before using it to secure the connection between Traefik and the backends.
|
||||
|
||||
### `terminationDelay`
|
||||
|
||||
As a proxy between a client and a server, it can happen that either side (e.g. client side) decides to terminate its writing capability on the connection (i.e. issuance of a FIN packet).
|
||||
The proxy needs to propagate that intent to the other side, and so when that happens, it also does the same on its connection with the other side (e.g. backend side).
|
||||
|
||||
However, if for some reason (bad implementation, or malicious intent) the other side does not eventually do the same as well,
|
||||
the connection would stay half-open, which would lock resources for however long.
|
||||
|
||||
To that end, as soon as the proxy enters this termination sequence, it sets a deadline on fully terminating the connections on both sides.
|
||||
|
||||
The termination delay controls that deadline.
|
||||
A negative value means an infinite deadline (i.e. the connection is never fully terminated by the proxy itself).
|
104
docs/content/reference/routing-configuration/tcp/service.md
Normal file
104
docs/content/reference/routing-configuration/tcp/service.md
Normal file
@ -0,0 +1,104 @@
|
||||
---
|
||||
title: "Traefik TCP Services Documentation"
|
||||
description: "A service is in charge of connecting incoming requests to the Servers that can handle them. Read the technical documentation."
|
||||
---
|
||||
|
||||
## General
|
||||
|
||||
Each of the fields of the service section represents a kind of service. Which means, that for each specified service, one of the fields, and only one, has to be enabled to define what kind of service is created. Currently, the two available kinds are `LoadBalancer`, and `Weighted`.
|
||||
|
||||
## Servers Load Balancer
|
||||
|
||||
The servers load balancer is in charge of balancing the requests between the servers of the same service.
|
||||
|
||||
### Configuration Examples
|
||||
|
||||
Declaring a Service with Two Servers -- Using the [File Provider](../../install-configuration/providers/others/file.md)
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tcp.services]
|
||||
[tcp.services.my-service.loadBalancer]
|
||||
[[tcp.services.my-service.loadBalancer.servers]]
|
||||
address = "xx.xx.xx.xx:xx"
|
||||
[[tcp.services.my-service.loadBalancer.servers]]
|
||||
address = "xx.xx.xx.xx:xx"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default |
|
||||
|----------|------------------------------------------|--------- |
|
||||
| `servers` | Servers declare a single instance of your program. | "" |
|
||||
| `servers.address` | The address option (IP:Port) point to a specific instance. | "" |
|
||||
| `servers.tls` | The `tls` option determines whether to use TLS when dialing with the backend. | false |
|
||||
| `servers.serversTransport` | `serversTransport` allows to reference a TCP [ServersTransport](./serverstransport.md configuration for the communication between Traefik and your servers. If no serversTransport is specified, the default@internal will be used. | "" |
|
||||
| `servers.proxyProtocol.version` | Traefik supports PROXY Protocol version 1 and 2 on TCP Services. More Information [here](#serversproxyprotocolversion) | 2 |
|
||||
|
||||
### servers.proxyProtocol.version
|
||||
|
||||
Traefik supports [PROXY Protocol](https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt) version 1 and 2 on TCP Services. It can be enabled by setting `proxyProtocol` on the load balancer.
|
||||
The option specifies the version of the protocol to be used. Either 1 or 2.
|
||||
|
||||
## Weighted Round Robin
|
||||
|
||||
The Weighted Round Robin (alias `WRR`) load-balancer of services is in charge of balancing the requests between multiple services based on provided weights.
|
||||
|
||||
This strategy is only available to load balance between [services](./service.md) and not between servers.
|
||||
|
||||
!!! info "Supported Providers"
|
||||
|
||||
This strategy can be defined currently with the [File](../../install-configuration/providers/others/file.md) or [IngressRoute](../../install-configuration/providers/kubernetes/kubernetes-crd.md) providers.
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
services:
|
||||
app:
|
||||
weighted:
|
||||
services:
|
||||
- name: appv1
|
||||
weight: 3
|
||||
- name: appv2
|
||||
weight: 1
|
||||
|
||||
appv1:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "xxx.xxx.xxx.xxx:8080"
|
||||
|
||||
appv2:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "xxx.xxx.xxx.xxx:8080"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tcp.services]
|
||||
[tcp.services.app]
|
||||
[[tcp.services.app.weighted.services]]
|
||||
name = "appv1"
|
||||
weight = 3
|
||||
[[tcp.services.app.weighted.services]]
|
||||
name = "appv2"
|
||||
weight = 1
|
||||
|
||||
[tcp.services.appv1]
|
||||
[tcp.services.appv1.loadBalancer]
|
||||
[[tcp.services.appv1.loadBalancer.servers]]
|
||||
address = "private-ip-server-1:8080/"
|
||||
|
||||
[tcp.services.appv2]
|
||||
[tcp.services.appv2.loadBalancer]
|
||||
[[tcp.services.appv2.loadBalancer.servers]]
|
||||
address = "private-ip-server-2:8080/"
|
||||
```
|
||||
|
104
docs/content/reference/routing-configuration/tcp/tls.md
Normal file
104
docs/content/reference/routing-configuration/tcp/tls.md
Normal file
@ -0,0 +1,104 @@
|
||||
---
|
||||
title: "Traefik TLS Documentation"
|
||||
description: "Learn how to configure the transport layer security (TLS) connection for TCP services in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
## General
|
||||
|
||||
When a router is configured to handle HTTPS traffic, include a `tls` field in its definition. This field tells Traefik that the router should process only TLS requests and ignore non-TLS traffic.
|
||||
|
||||
By default, a router with a TLS field will terminate the TLS connections, meaning that it will send decrypted data to the services.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
tcp:
|
||||
routers:
|
||||
my-tls-router:
|
||||
rule: "HostSNI(`example.com`)"
|
||||
service: "my-tcp-service"
|
||||
tls:
|
||||
passthrough: true
|
||||
options: "my-tls-options"
|
||||
domains:
|
||||
- main: "example.com"
|
||||
sans:
|
||||
- "www.example.com"
|
||||
- "api.example.com"
|
||||
certResolver: "myresolver"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[tcp.routers.my-tls-router]
|
||||
rule = "HostSNI(`example.com`)"
|
||||
service = "my-tcp-service"
|
||||
|
||||
[tcp.routers.my-tls-router.tls]
|
||||
passthrough = true
|
||||
options = "my-tls-options"
|
||||
certResolver = "myresolver"
|
||||
|
||||
[[tcp.routers.my-tls-router.tls.domains]]
|
||||
main = "example.com"
|
||||
sans = ["www.example.com", "api.example.com"]
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.tcp.routers.my-tls-router.tls=true"
|
||||
- "traefik.tcp.routers.my-tls-router.rule=HostSNI(`example.com`)"
|
||||
- "traefik.tcp.routers.my-tls-router.service=my-tcp-service"
|
||||
- "traefik.tcp.routers.my-tls-router.tls.passthrough=true"
|
||||
- "traefik.tcp.routers.my-tls-router.tls.options=my-tls-options"
|
||||
- "traefik.tcp.routers.my-tls-router.tls.certResolver=myresolver"
|
||||
- "traefik.tcp.routers.my-tls-router.tls.domains[0].main=example.com"
|
||||
- "traefik.tcp.routers.my-tls-router.tls.domains[0].sans=www.example.com,api.example.com"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.tcp.routers.my-tls-router.tls=true"
|
||||
"traefik.tcp.routers.my-tls-router.rule=HostSNI(`example.com`)",
|
||||
"traefik.tcp.routers.my-tls-router.service=my-tcp-service",
|
||||
"traefik.tcp.routers.my-tls-router.tls.passthrough=true",
|
||||
"traefik.tcp.routers.my-tls-router.tls.options=my-tls-options",
|
||||
"traefik.tcp.routers.my-tls-router.tls.certResolver=myresolver",
|
||||
"traefik.tcp.routers.my-tls-router.tls.domains[0].main=example.com",
|
||||
"traefik.tcp.routers.my-tls-router.tls.domains[0].sans=www.example.com,api.example.com"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
??? info "Postgres STARTTLS"
|
||||
|
||||
Traefik supports the Postgres STARTTLS protocol,
|
||||
which allows TLS routing for Postgres connections.
|
||||
|
||||
To do so, Traefik reads the first bytes sent by a Postgres client,
|
||||
identifies if they correspond to the message of a STARTTLS negotiation,
|
||||
and, if so, acknowledges and signals the client that it can start the TLS handshake.
|
||||
|
||||
Please note/remember that there are subtleties inherent to STARTTLS in whether the connection ends up being a TLS one or not.
|
||||
These subtleties depend on the `sslmode` value in the client configuration (and on the server authentication rules).
|
||||
Therefore, it is recommended to use the `require` value for the `sslmode`.
|
||||
|
||||
Afterwards, the TLS handshake, and routing based on TLS, can proceed as expected.
|
||||
|
||||
!!! warning "Postgres STARTTLS with TCP TLS PassThrough routers"
|
||||
|
||||
As mentioned above, the `sslmode` configuration parameter does have an impact on whether a STARTTLS session will succeed.
|
||||
In particular in the context of TCP TLS PassThrough, some of the values (such as `allow`) do not even make sense.
|
||||
Which is why, once more it is recommended to use the `require` value.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Field | Description | Default | Required |
|
||||
|:------------------|:--------------------|:-----------------------------------------------|:---------|
|
||||
|`passthrough`| Defines whether the requests should be forwarded "as is", keeping all data encrypted. | false | No |
|
||||
|`options`| enables fine-grained control of the TLS parameters. It refers to a [TLS Options](../http/tls/tls-certificates.md#tls-options) and will be applied only if a `HostSNI` rule is defined. | "" | No |
|
||||
|`domains`| Defines a set of SANs (alternative domains) for each main domain. Every domain must have A/AAAA records pointing to Traefik. Each domain & SAN will lead to a certificate request.| [] | No |
|
||||
|`certResolver`| If defined, Traefik will try to generate certificates based on routers `Host` & `HostSNI` rules. | "" | No |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "Traefik UDP Routers Rules & Priority Documentation"
|
||||
description: "In Traefik Proxy, a router is in charge of connecting incoming requests to the Services that can handle them. Read the technical documentation."
|
||||
---
|
||||
|
||||
A router is in charge of connecting incoming requests to the services that can handle them.
|
||||
In the process, routers may use pieces of [middleware](../../http/middlewares/overview.md) to update the request,
|
||||
or act before forwarding the request to the service.
|
||||
|
||||
Similarly to TCP, as UDP is the transport layer, there is no concept of a request,
|
||||
so there is no notion of an URL path prefix to match an incoming UDP packet with.
|
||||
Furthermore, as there is no good TLS support at the moment for multiple hosts,
|
||||
there is no Host SNI notion to match against either.
|
||||
Therefore, there is no criterion that could be used as a rule to match incoming packets in order to route them.
|
||||
So UDP _routers_ at this time are pretty much only load-balancers in one form or another.
|
||||
|
||||
!!! tip
|
||||
UDP routers can only target UDP services (and not HTTP or TCP services).
|
||||
|
||||
## Sessions and timeout
|
||||
|
||||
Even though UDP is connectionless (and because of that),
|
||||
the implementation of an UDP router in Traefik relies on what we (and a couple of other implementations) call a `session`.
|
||||
It means that some state is kept about an ongoing communication between a client and a backend,
|
||||
notably so that the proxy knows where to forward a response packet from a backend.
|
||||
|
||||
As expected, a `timeout` is associated to each of these sessions,
|
||||
so that they get cleaned out if they go through a period of inactivity longer than a given duration.
|
||||
|
||||
Timeout can be configured using the `entryPoints.name.udp.timeout` option as described under [EntryPoints](../../../install-configuration/entrypoints.md)
|
||||
|
||||
## EntryPoints
|
||||
|
||||
If not specified, UDP routers will accept packets from all defined (UDP) EntryPoints. If one wants to limit the router scope to a set of EntryPoints, one should set the `entryPoints` option.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Listens to Every Entry Point
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
udp:
|
||||
routers:
|
||||
Router-1:
|
||||
# By default, routers listen to all UDP entrypoints
|
||||
# i.e. "other", and "streaming".
|
||||
service: "service-1"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[udp.routers]
|
||||
[udp.routers.Router-1]
|
||||
# By default, routers listen to all UDP entrypoints,
|
||||
# i.e. "other", and "streaming".
|
||||
service = "service-1"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.udp.routers.Router-1.service=service-1"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.udp.routers.Router-1.service=service-1"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Listens to Specific EntryPoints
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
udp:
|
||||
routers:
|
||||
Router-1:
|
||||
# does not listen on "other" entry point
|
||||
entryPoints:
|
||||
- "streaming"
|
||||
service: "service-1"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
[udp.routers]
|
||||
[udp.routers.Router-1]
|
||||
# does not listen on "other" entry point
|
||||
entryPoints = ["streaming"]
|
||||
service = "service-1"
|
||||
```
|
||||
|
||||
```yaml tab="Labels"
|
||||
labels:
|
||||
- "traefik.udp.routers.Router-1.entryPoints=streaming"
|
||||
- "traefik.udp.routers.Router-1.service=service-1"
|
||||
```
|
||||
|
||||
```json tab="Tags"
|
||||
{
|
||||
//...
|
||||
"Tags": [
|
||||
"traefik.udp.routers.Router-1.entryPoints=streaming",
|
||||
"traefik.udp.routers.Router-1.service=service-1"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
!!! info "Service"
|
||||
|
||||
There must be one (and only one) UDP [service](../service.md) referenced per UDP router.
|
||||
Services are the target for the router.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
44
docs/content/reference/routing-configuration/udp/service.md
Normal file
44
docs/content/reference/routing-configuration/udp/service.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Traefik UDP Services Documentation"
|
||||
description: "A service is in charge of connecting incoming requests to the Servers that can handle them. Read the technical documentation. Read the technical documentation."
|
||||
---
|
||||
|
||||
### General
|
||||
|
||||
Each of the fields of the service section represents a kind of service.
|
||||
Which means, that for each specified service, one of the fields, and only one,
|
||||
has to be enabled to define what kind of service is created.
|
||||
Currently, the available kind is `LoadBalancer`.
|
||||
|
||||
## Servers Load Balancer
|
||||
|
||||
The servers load balancer is in charge of balancing the requests between the servers of the same service.
|
||||
|
||||
### Servers
|
||||
|
||||
The Servers field defines all the servers that are part of this load-balancing group,
|
||||
i.e. each address (IP:Port) on which an instance of the service's program is deployed.
|
||||
|
||||
#### Configuration Example
|
||||
|
||||
A Service with One Server -- Using the [File Provider](../../install-configuration/providers/others/file.md)
|
||||
|
||||
```yaml tab="Structured (YAML)"
|
||||
## Dynamic configuration
|
||||
udp:
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- address: "xx.xx.xx.xx:xx"
|
||||
```
|
||||
|
||||
```toml tab="Structured (TOML)"
|
||||
## Dynamic configuration
|
||||
[udp.services]
|
||||
[udp.services.my-service.loadBalancer]
|
||||
[[udp.services.my-service.loadBalancer.servers]]
|
||||
address = "xx.xx.xx.xx:xx"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
@ -229,15 +229,85 @@ nav:
|
||||
- 'Logs & AccessLogs': 'reference/install-configuration/observability/logs-and-accesslogs.md'
|
||||
- 'Health Check (CLI & Ping)': 'reference/install-configuration/observability/healthcheck.md'
|
||||
# - 'Options List': 'reference/install-configuration/cli-options-list.md' -- Todo
|
||||
- 'Dynamic Configuration':
|
||||
- 'File': 'reference/dynamic-configuration/file.md'
|
||||
- 'Docker': 'reference/dynamic-configuration/docker.md'
|
||||
- 'Swarm': 'reference/dynamic-configuration/swarm.md'
|
||||
- 'Kubernetes CRD': 'reference/dynamic-configuration/kubernetes-crd.md'
|
||||
- 'Consul Catalog': 'reference/dynamic-configuration/consul-catalog.md'
|
||||
- 'Nomad': "reference/dynamic-configuration/nomad.md"
|
||||
- 'ECS': 'reference/dynamic-configuration/ecs.md'
|
||||
- 'KV': 'reference/dynamic-configuration/kv.md'
|
||||
- 'Routing Configuration':
|
||||
- 'General' :
|
||||
- 'Configuration Methods' : 'reference/routing-configuration/dynamic-configuration-methods.md'
|
||||
- 'HTTP' :
|
||||
- 'Router' :
|
||||
- 'Rules & Priority' : 'reference/routing-configuration/http/router/rules-and-priority.md'
|
||||
- 'Observability': 'reference/routing-configuration/http/router/observability.md'
|
||||
- 'Load Balancing' :
|
||||
- 'Service' : 'reference/routing-configuration/http/load-balancing/service.md'
|
||||
- 'ServersTransport' : 'reference/routing-configuration/http/load-balancing/serverstransport.md'
|
||||
- 'TLS' :
|
||||
- 'Overview' : 'reference/routing-configuration/http/tls/overview.md'
|
||||
- 'TLS Certificates' : 'reference/routing-configuration/http/tls/tls-certificates.md'
|
||||
- 'TLS Options' : 'reference/routing-configuration/http/tls/tls-options.md'
|
||||
- 'Middlewares' :
|
||||
- 'Overview' : 'reference/routing-configuration/http/middlewares/overview.md'
|
||||
- 'AddPrefix' : 'reference/routing-configuration/http/middlewares/addprefix.md'
|
||||
- 'BasicAuth' : 'reference/routing-configuration/http/middlewares/basicauth.md'
|
||||
- 'Buffering': 'reference/routing-configuration/http/middlewares/buffering.md'
|
||||
- 'Chain': 'reference/routing-configuration/http/middlewares/chain.md'
|
||||
- 'Circuit Breaker' : 'reference/routing-configuration/http/middlewares/circuitbreaker.md'
|
||||
- 'Compress': 'reference/routing-configuration/http/middlewares/compress.md'
|
||||
- 'ContentType': 'reference/routing-configuration/http/middlewares/contenttype.md'
|
||||
- 'DigestAuth': 'reference/routing-configuration/http/middlewares/digestauth.md'
|
||||
- 'Errors': 'reference/routing-configuration/http/middlewares/errorpages.md'
|
||||
- 'ForwardAuth': 'reference/routing-configuration/http/middlewares/forwardauth.md'
|
||||
- 'GrpcWeb': 'reference/routing-configuration/http/middlewares/grpcweb.md'
|
||||
- 'Headers': 'reference/routing-configuration/http/middlewares/headers.md'
|
||||
- 'IPAllowList': 'reference/routing-configuration/http/middlewares/ipallowlist.md'
|
||||
- 'InFlightReq': 'reference/routing-configuration/http/middlewares/inflightreq.md'
|
||||
- 'PassTLSClientCert': 'reference/routing-configuration/http/middlewares/passtlsclientcert.md'
|
||||
- 'RateLimit': 'reference/routing-configuration/http/middlewares/ratelimit.md'
|
||||
- 'RedirectRegex': 'reference/routing-configuration/http/middlewares/redirectregex.md'
|
||||
- 'RedirectScheme': 'reference/routing-configuration/http/middlewares/redirectscheme.md'
|
||||
- 'ReplacePath': 'reference/routing-configuration/http/middlewares/replacepath.md'
|
||||
- 'ReplacePathRegex': 'reference/routing-configuration/http/middlewares/replacepathregex.md'
|
||||
- 'Retry': 'reference/routing-configuration/http/middlewares/retry.md'
|
||||
- 'StripPrefix': 'reference/routing-configuration/http/middlewares/stripprefix.md'
|
||||
- 'StripPrefixRegex': 'reference/routing-configuration/http/middlewares/stripprefixregex.md'
|
||||
- 'TCP' :
|
||||
- 'Router' :
|
||||
- 'Rules & Priority' : 'reference/routing-configuration/tcp/router/rules-and-priority.md'
|
||||
- 'Service' : 'reference/routing-configuration/tcp/service.md'
|
||||
- 'ServersTransport' : 'reference/routing-configuration/tcp/serverstransport.md'
|
||||
- 'TLS' : 'reference/routing-configuration/tcp/tls.md'
|
||||
- 'Middlewares' :
|
||||
- 'Overview' : 'reference/routing-configuration/tcp/middlewares/overview.md'
|
||||
- 'InFlightConn' : 'reference/routing-configuration/tcp/middlewares/inflightconn.md'
|
||||
- 'IPAllowList' : 'reference/routing-configuration/tcp/middlewares/ipallowlist.md'
|
||||
- 'UDP' :
|
||||
- 'Router' :
|
||||
- 'Rules & Priority' : 'reference/routing-configuration/udp/router/rules-priority.md'
|
||||
- 'Service' : 'reference/routing-configuration/udp/service.md'
|
||||
- 'Kubernetes':
|
||||
- 'Gateway API' : 'reference/routing-configuration/kubernetes/gateway-api.md'
|
||||
- 'Kubernetes CRD' :
|
||||
- 'HTTP' :
|
||||
- 'IngressRoute' : 'reference/routing-configuration/kubernetes/crd/http/ingressroute.md'
|
||||
- 'TraefikService' : 'reference/routing-configuration/kubernetes/crd/http/traefikservice.md'
|
||||
- 'ServersTransport' : 'reference/routing-configuration/kubernetes/crd/http/serverstransport.md'
|
||||
- 'Middleware' : 'reference/routing-configuration/kubernetes/crd/http/middleware.md'
|
||||
- 'TLSOption' : 'reference/routing-configuration/kubernetes/crd/http/tlsoption.md'
|
||||
- 'TLSStore' : 'reference/routing-configuration/kubernetes/crd/http/tlsstore.md'
|
||||
- 'TCP' :
|
||||
- 'IngressRouteTCP' : 'reference/routing-configuration/kubernetes/crd/tcp/ingressroutetcp.md'
|
||||
- 'ServersTransportTCP' : 'reference/routing-configuration/kubernetes/crd/tcp/serverstransporttcp.md'
|
||||
- 'MiddlewareTCP' : 'reference/routing-configuration/kubernetes/crd/tcp/middlewaretcp.md'
|
||||
- 'TLSOption' : 'reference/routing-configuration/kubernetes/crd/tcp/tlsoption.md'
|
||||
- 'TLSStore' : 'reference/routing-configuration/kubernetes/crd/tcp/tlsstore.md'
|
||||
- 'UDP' :
|
||||
- 'IngressRouteUDP' : 'reference/routing-configuration/kubernetes/crd/udp/ingressrouteudp.md'
|
||||
- 'Ingress' : 'reference/routing-configuration/kubernetes/ingress.md'
|
||||
- 'Label & Tag Providers' :
|
||||
- 'Docker' : 'reference/routing-configuration/other-providers/docker.md'
|
||||
- 'Swarm' : 'reference/routing-configuration/other-providers/swarm.md'
|
||||
- 'Consul Catalog' : 'reference/routing-configuration/other-providers/consul-catalog.md'
|
||||
- 'Nomad' : 'reference/routing-configuration/other-providers/nomad.md'
|
||||
- 'ECS' : 'reference/routing-configuration/other-providers/ecs.md'
|
||||
- 'KV' : 'reference/routing-configuration/other-providers/kv.md'
|
||||
- 'Deprecation Notices':
|
||||
- 'Releases': 'deprecation/releases.md'
|
||||
- 'Features': 'deprecation/features.md'
|
||||
|
40
go.mod
40
go.mod
@ -8,7 +8,13 @@ require (
|
||||
github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000 // No tag on the repo.
|
||||
github.com/andybalholm/brotli v1.1.1
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||
github.com/aws/aws-sdk-go v1.44.327
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.2
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.203.1
|
||||
github.com/aws/aws-sdk-go-v2/service/ecs v1.53.15
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13
|
||||
github.com/aws/smithy-go v1.22.2
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd // No tag on the repo.
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
@ -17,7 +23,7 @@ require (
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/fsnotify/fsnotify v1.8.0
|
||||
github.com/go-acme/lego/v4 v4.21.0
|
||||
github.com/go-acme/lego/v4 v4.22.2
|
||||
github.com/go-kit/kit v0.13.0
|
||||
github.com/go-kit/log v0.2.1
|
||||
github.com/golang/protobuf v1.5.4
|
||||
@ -64,7 +70,7 @@ require (
|
||||
github.com/tetratelabs/wazero v1.8.0
|
||||
github.com/tidwall/gjson v1.17.0
|
||||
github.com/traefik/grpc-web v0.16.0
|
||||
github.com/traefik/paerser v0.2.1
|
||||
github.com/traefik/paerser v0.2.2
|
||||
github.com/traefik/yaegi v0.16.1
|
||||
github.com/unrolled/render v1.0.2
|
||||
github.com/unrolled/secure v1.0.9
|
||||
@ -92,7 +98,7 @@ require (
|
||||
golang.org/x/mod v0.22.0
|
||||
golang.org/x/net v0.33.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/sys v0.29.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/time v0.8.0
|
||||
golang.org/x/tools v0.28.0
|
||||
@ -144,21 +150,17 @@ require (
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.72 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect
|
||||
github.com/aws/smithy-go v1.22.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
@ -170,7 +172,6 @@ require (
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/cpu/goacmedns v0.1.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
||||
@ -190,7 +191,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@ -282,6 +283,7 @@ require (
|
||||
github.com/nrdcg/desec v0.10.0 // indirect
|
||||
github.com/nrdcg/dnspod-go v0.4.0 // indirect
|
||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||
github.com/nrdcg/goacmedns v0.2.0 // indirect
|
||||
github.com/nrdcg/goinwx v0.10.0 // indirect
|
||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||
@ -360,10 +362,10 @@ require (
|
||||
go.uber.org/ratelimit v0.3.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/arch v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||
golang.org/x/oauth2 v0.24.0 // indirect
|
||||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
google.golang.org/api v0.214.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
|
74
go.sum
74
go.sum
@ -149,41 +149,45 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.44.327 h1:ZS8oO4+7MOBLhkdwIhgtVeDzCeWOlTfKJS7EgggbIEY=
|
||||
github.com/aws/aws-sdk-go v1.44.327/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.203.1 h1:ZgY9zeVAe+54Qa7o1GXKRNTez79lffCeJSSinhl+qec=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.203.1/go.mod h1:0naMk66LtdeTmE+1CWQTKwtzOQ2t8mavOhMhR0Pv1m0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecs v1.53.15 h1:uH0DMwDjLGgjjYMk3M1MXHggk37trTiJIvwyJNP17Ig=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecs v1.53.15/go.mod h1:49tE5yYdlAHqZIO8u5+u9Xy9k8IaV0v5cstZrjnX5+c=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 h1:2scbY6//jy/s8+5vGrk7l1+UtHl0h9A4MjOO2k/TM2E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14/go.mod h1:bRpZPHZpSe5YRHmPfK3h1M7UBFCn2szHzyx0rw04zro=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.8 h1:+lmJoqxuUoPlSfGk5JYQQivd9YFjUvRZR6RPY+Wcx48=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.8/go.mod h1:Gg8/myP4+rgRi4+j9gQdbOEnMtwMAUUIeXo+nKCFVj8=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.4 h1:0jMtawybbfpFEIMy4wvfyW2Z4YLr7mnuzT0fhR67Nrc=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.4/go.mod h1:xlMODgumb0Pp8bzfpojqelDrf8SL9rb5ovwmwKJl+oU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13 h1:JfPeW7F6Y+VqBg6p+8zQv4wlgceguYu5ZT0USEGZ89g=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.13/go.mod h1:EonGQFn66wZkJJrrKXrryrxoS3V30rcHvaWvc6oGHCI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.11 h1:kuIyu4fTT38Kj7YCC7ouNbVZSSpqkZ+LzIfhCr6Dg+I=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.11/go.mod h1:Ro744S4fKiCCuZECXgOi760TiYylUM8ZBf6OGiZzJtY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.10 h1:l+dgv/64iVlQ3WsBbnn+JSbkj01jIi+SM0wYsj3y/hY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.10/go.mod h1:Fzsj6lZEb8AkTE5S68OhcbBqeWPsR8RnGuKPr8Todl8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9 h1:BRVDbewN6VZcwr+FBOszDKvYeXY1kJ+GGMCcpghlw0U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9/go.mod h1:f6vjfZER1M17Fokn0IzssOTMT2N8ZSq+7jnNF0tArvw=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@ -259,8 +263,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpu/goacmedns v0.1.1 h1:DM3H2NiN2oam7QljgGY5ygy4yDXhK5Z4JUnqaugs2C4=
|
||||
github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobeGqugQ=
|
||||
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
|
||||
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@ -357,8 +359,8 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-acme/lego/v4 v4.21.0 h1:arEW+8o5p7VI8Bk1kr/PDlgD1DrxtTH1gJ4b7mehL8o=
|
||||
github.com/go-acme/lego/v4 v4.21.0/go.mod h1:HrSWzm3Ckj45Ie3i+p1zKVobbQoMOaGu9m4up0dUeDI=
|
||||
github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0=
|
||||
github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
@ -366,8 +368,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
|
||||
@ -905,6 +907,8 @@ github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U
|
||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc=
|
||||
github.com/nrdcg/freemyip v0.3.0/go.mod h1:c1PscDvA0ukBF0dwelU/IwOakNKnVxetpAQ863RMJoM=
|
||||
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
|
||||
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
||||
github.com/nrdcg/goinwx v0.10.0 h1:6W630bjDxQD6OuXKqrFRYVpTt0G/9GXXm3CeOrN0zJM=
|
||||
github.com/nrdcg/goinwx v0.10.0/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4=
|
||||
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
|
||||
@ -1187,8 +1191,8 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
|
||||
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
|
||||
github.com/traefik/paerser v0.2.1 h1:LFgeak1NmjEHF53c9ENdXdL1UMkF/lD5t+7Evsz4hH4=
|
||||
github.com/traefik/paerser v0.2.1/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
|
||||
github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ=
|
||||
github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
|
||||
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
|
||||
github.com/traefik/yaegi v0.16.1/go.mod h1:4eVhbPb3LnD2VigQjhYbEJ69vDRFdT2HQNrXx8eEwUY=
|
||||
github.com/transip/gotransip/v6 v6.26.0 h1:Aejfvh8rSp8Mj2GX/RpdBjMCv+Iy/DmgfNgczPDP550=
|
||||
@ -1386,8 +1390,8 @@ golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIi
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
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=
|
||||
@ -1483,7 +1487,6 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
@ -1604,12 +1607,11 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
@ -1617,8 +1619,8 @@ golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
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=
|
||||
|
57
integration/fixtures/acme/acme_domains_1712362990.toml
Normal file
57
integration/fixtures/acme/acme_domains_1712362990.toml
Normal file
@ -0,0 +1,57 @@
|
||||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
noColor = true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":5002"
|
||||
[entryPoints.websecure]
|
||||
address = ":5001"
|
||||
|
||||
|
||||
|
||||
[certificatesResolvers.default.acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "/tmp/acme.json"
|
||||
keyType = ""
|
||||
caServer = "https://172.31.42.2:14000/dir"
|
||||
|
||||
|
||||
|
||||
|
||||
[certificatesResolvers.default.acme.tlsChallenge]
|
||||
|
||||
|
||||
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[providers.file]
|
||||
filename = "fixtures/acme/acme_domains_1712362990.toml"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.services]
|
||||
[http.services.test.loadBalancer]
|
||||
[[http.services.test.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:9010"
|
||||
|
||||
[http.routers]
|
||||
[http.routers.test]
|
||||
entryPoints = ["websecure"]
|
||||
rule = "PathPrefix(`/`)"
|
||||
service = "test"
|
||||
[http.routers.test.tls]
|
||||
certResolver = "default"
|
||||
|
||||
[[http.routers.test.tls.domains]]
|
||||
main = "acme.wtf"
|
||||
sans = [
|
||||
"traefik.acme.wtf",
|
||||
]
|
||||
|
@ -50,7 +50,7 @@
|
||||
Rule = "Path(`/basic`)"
|
||||
[http.routers.router1]
|
||||
Service = "service1"
|
||||
Middlewares = ["retry", "ratelimit-1"]
|
||||
Middlewares = ["ratelimit-1"]
|
||||
Rule = "Path(`/ratelimit`)"
|
||||
[http.routers.router2]
|
||||
Service = "service2"
|
||||
@ -58,8 +58,12 @@
|
||||
Rule = "Path(`/retry`)"
|
||||
[http.routers.router3]
|
||||
Service = "service3"
|
||||
Middlewares = ["retry", "basic-auth"]
|
||||
Middlewares = ["basic-auth"]
|
||||
Rule = "Path(`/auth`)"
|
||||
[http.routers.router4]
|
||||
Service = "service4"
|
||||
Middlewares = ["retry", "basic-auth"]
|
||||
Rule = "Path(`/retry-auth`)"
|
||||
[http.routers.customPing]
|
||||
entryPoints = ["web"]
|
||||
rule = "PathPrefix(`/ping`)"
|
||||
@ -98,3 +102,9 @@
|
||||
passHostHeader = true
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
||||
[http.services.service4]
|
||||
[http.services.service4.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service4.loadBalancer.servers]]
|
||||
url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}"
|
||||
|
@ -77,7 +77,7 @@ func (s *TracingSuite) TearDownTest() {
|
||||
s.composeStop("tempo")
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetryBasic_HTTP() {
|
||||
func (s *TracingSuite) TestOpenTelemetryBasic_HTTP() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
@ -144,7 +144,7 @@ func (s *TracingSuite) TestOpentelemetryBasic_HTTP() {
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetryBasic_gRPC() {
|
||||
func (s *TracingSuite) TestOpenTelemetryBasic_gRPC() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
@ -201,7 +201,7 @@ func (s *TracingSuite) TestOpentelemetryBasic_gRPC() {
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetryRateLimit() {
|
||||
func (s *TracingSuite) TestOpenTelemetryRateLimit() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
@ -248,48 +248,26 @@ func (s *TracingSuite) TestOpentelemetryRateLimit() {
|
||||
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.1.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.2.name": "RateLimiter",
|
||||
"batches.0.scopeSpans.0.spans.2.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.3.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.resend_count\").value.intValue": "1",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.4.name": "RateLimiter",
|
||||
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.request.resend_count\").value.intValue": "2",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.6.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.7.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.8.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.response.status_code\").value.intValue": "429",
|
||||
"batches.0.scopeSpans.0.spans.3.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "429",
|
||||
},
|
||||
{
|
||||
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
||||
@ -318,37 +296,33 @@ func (s *TracingSuite) TestOpentelemetryRateLimit() {
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.4.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.4.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.6.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.7.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
||||
"batches.0.scopeSpans.0.spans.6.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
||||
},
|
||||
}
|
||||
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetryRetry() {
|
||||
func (s *TracingSuite) TestOpenTelemetryRetry() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: 81,
|
||||
@ -471,7 +445,7 @@ func (s *TracingSuite) TestOpentelemetryRetry() {
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetryAuth() {
|
||||
func (s *TracingSuite) TestOpenTelemetryAuth() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
@ -498,59 +472,90 @@ func (s *TracingSuite) TestOpentelemetryAuth() {
|
||||
"batches.0.scopeSpans.0.spans.0.status.message": "Authentication failed",
|
||||
"batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.1.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.1.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.2.name": "BasicAuth",
|
||||
"batches.0.scopeSpans.0.spans.2.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
|
||||
"batches.0.scopeSpans.0.spans.2.status.message": "Authentication failed",
|
||||
"batches.0.scopeSpans.0.spans.2.status.code": "STATUS_CODE_ERROR",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.3.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.resend_count\").value.intValue": "1",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.4.name": "BasicAuth",
|
||||
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
|
||||
"batches.0.scopeSpans.0.spans.4.status.message": "Authentication failed",
|
||||
"batches.0.scopeSpans.0.spans.4.status.code": "STATUS_CODE_ERROR",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.request.resend_count\").value.intValue": "2",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.6.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.7.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.8.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.path\").value.stringValue": "/auth",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.response.status_code\").value.intValue": "401",
|
||||
"batches.0.scopeSpans.0.spans.3.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.path\").value.stringValue": "/auth",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "401",
|
||||
},
|
||||
}
|
||||
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpentelemetrySafeURL() {
|
||||
func (s *TracingSuite) TestOpenTelemetryAuthWithRetry() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
IP: s.otelCollectorIP,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
// wait for traefik
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/retry-auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
contains := []map[string]string{
|
||||
{
|
||||
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.0.name": "BasicAuth",
|
||||
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
|
||||
"batches.0.scopeSpans.0.spans.0.status.message": "Authentication failed",
|
||||
"batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.1.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.2.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service4@file",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.router.name\").value.stringValue": "router4@file",
|
||||
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"http.route\").value.stringValue": "Path(`/retry-auth`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.3.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.4.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.path\").value.stringValue": "/retry-auth",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.query\").value.stringValue": "",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.response.status_code\").value.intValue": "401",
|
||||
},
|
||||
}
|
||||
|
||||
s.checkTraceContent(contains)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestOpenTelemetrySafeURL() {
|
||||
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
|
||||
WhoamiIP: s.whoamiIP,
|
||||
WhoamiPort: s.whoamiPort,
|
||||
@ -593,30 +598,26 @@ func (s *TracingSuite) TestOpentelemetrySafeURL() {
|
||||
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.4.name": "Retry",
|
||||
"batches.0.scopeSpans.0.spans.4.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
|
||||
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Router",
|
||||
"batches.0.scopeSpans.0.spans.5.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
|
||||
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.6.name": "Metrics",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
|
||||
|
||||
"batches.0.scopeSpans.0.spans.7.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.path\").value.stringValue": "/auth",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.query\").value.stringValue": "api_key=REDACTED",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
||||
"batches.0.scopeSpans.0.spans.6.name": "EntryPoint",
|
||||
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_SERVER",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"entry_point\").value.stringValue": "web",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"url.path\").value.stringValue": "/auth",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"url.query\").value.stringValue": "api_key=REDACTED",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
|
||||
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func NewAWSWrapper(logger zerolog.Logger) aws.LoggerFunc {
|
||||
func NewAWSWrapper(logger zerolog.Logger) logging.LoggerFunc {
|
||||
if logger.GetLevel() > zerolog.DebugLevel {
|
||||
return func(args ...interface{}) {}
|
||||
return func(classification logging.Classification, format string, args ...interface{}) {}
|
||||
}
|
||||
|
||||
return func(args ...interface{}) {
|
||||
return func(classification logging.Classification, format string, args ...interface{}) {
|
||||
logger.Debug().CallerSkipFrame(2).MsgFunc(msgFunc(args...))
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -18,7 +19,7 @@ func TestNewAWSWrapper(t *testing.T) {
|
||||
|
||||
logger := NewAWSWrapper(zerolog.New(out).With().Caller().Logger())
|
||||
|
||||
logger.Log("foo")
|
||||
logger.Logf(logging.Debug, "%s", "foo")
|
||||
|
||||
assert.Equal(t, "<nil> DBG aws_test.go:21 > foo\n", buf.String())
|
||||
assert.Equal(t, "<nil> DBG aws_test.go:22 > foo\n", buf.String())
|
||||
}
|
||||
|
@ -609,83 +609,106 @@ func TestMinResponseBodyBytes(t *testing.T) {
|
||||
func Test1xxResponses(t *testing.T) {
|
||||
fakeBody := generateBytes(100000)
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h := w.Header()
|
||||
h.Add("Link", "</style.css>; rel=preload; as=style")
|
||||
h.Add("Link", "</script.js>; rel=preload; as=script")
|
||||
w.WriteHeader(http.StatusEarlyHints)
|
||||
|
||||
h.Add("Link", "</foo.js>; rel=preload; as=script")
|
||||
w.WriteHeader(http.StatusProcessing)
|
||||
|
||||
if _, err := w.Write(fakeBody); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
cfg := dynamic.Compress{
|
||||
MinResponseBodyBytes: 1024,
|
||||
Encodings: defaultSupportedEncodings,
|
||||
}
|
||||
compress, err := New(context.Background(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(compress)
|
||||
t.Cleanup(server.Close)
|
||||
frontendClient := server.Client()
|
||||
|
||||
checkLinkHeaders := func(t *testing.T, expected, got []string) {
|
||||
t.Helper()
|
||||
|
||||
if len(expected) != len(got) {
|
||||
t.Errorf("Expected %d link headers; got %d", len(expected), len(got))
|
||||
}
|
||||
|
||||
for i := range expected {
|
||||
if i >= len(got) {
|
||||
t.Errorf("Expected %q link header; got nothing", expected[i])
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if expected[i] != got[i] {
|
||||
t.Errorf("Expected %q link header; got %q", expected[i], got[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var respCounter uint8
|
||||
trace := &httptrace.ClientTrace{
|
||||
Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
|
||||
switch code {
|
||||
case http.StatusEarlyHints:
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script"}, header["Link"])
|
||||
case http.StatusProcessing:
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script", "</foo.js>; rel=preload; as=script"}, header["Link"])
|
||||
default:
|
||||
t.Error("Unexpected 1xx response")
|
||||
}
|
||||
|
||||
respCounter++
|
||||
|
||||
return nil
|
||||
testCases := []struct {
|
||||
desc string
|
||||
encoding string
|
||||
}{
|
||||
{
|
||||
desc: "gzip",
|
||||
encoding: gzipName,
|
||||
},
|
||||
{
|
||||
desc: "brotli",
|
||||
encoding: brotliName,
|
||||
},
|
||||
{
|
||||
desc: "zstd",
|
||||
encoding: zstdName,
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req.Header.Add(acceptEncodingHeader, gzipName)
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h := w.Header()
|
||||
h.Add("Link", "</style.css>; rel=preload; as=style")
|
||||
h.Add("Link", "</script.js>; rel=preload; as=script")
|
||||
w.WriteHeader(http.StatusEarlyHints)
|
||||
|
||||
defer res.Body.Close()
|
||||
h.Add("Link", "</foo.js>; rel=preload; as=script")
|
||||
w.WriteHeader(http.StatusProcessing)
|
||||
|
||||
if respCounter != 2 {
|
||||
t.Errorf("Expected 2 1xx responses; got %d", respCounter)
|
||||
if _, err := w.Write(fakeBody); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
cfg := dynamic.Compress{
|
||||
MinResponseBodyBytes: 1024,
|
||||
Encodings: defaultSupportedEncodings,
|
||||
}
|
||||
compress, err := New(context.Background(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(compress)
|
||||
t.Cleanup(server.Close)
|
||||
frontendClient := server.Client()
|
||||
|
||||
checkLinkHeaders := func(t *testing.T, expected, got []string) {
|
||||
t.Helper()
|
||||
|
||||
if len(expected) != len(got) {
|
||||
t.Errorf("Expected %d link headers; got %d", len(expected), len(got))
|
||||
}
|
||||
|
||||
for i := range expected {
|
||||
if i >= len(got) {
|
||||
t.Errorf("Expected %q link header; got nothing", expected[i])
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if expected[i] != got[i] {
|
||||
t.Errorf("Expected %q link header; got %q", expected[i], got[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var respCounter uint8
|
||||
trace := &httptrace.ClientTrace{
|
||||
Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
|
||||
switch code {
|
||||
case http.StatusEarlyHints:
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script"}, header["Link"])
|
||||
case http.StatusProcessing:
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script", "</foo.js>; rel=preload; as=script"}, header["Link"])
|
||||
default:
|
||||
t.Error("Unexpected 1xx response")
|
||||
}
|
||||
|
||||
respCounter++
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req.Header.Add(acceptEncodingHeader, test.encoding)
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if respCounter != 2 {
|
||||
t.Errorf("Expected 2 1xx responses; got %d", respCounter)
|
||||
}
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script", "</foo.js>; rel=preload; as=script"}, res.Header["Link"])
|
||||
|
||||
assert.Equal(t, test.encoding, res.Header.Get(contentEncodingHeader))
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
assert.NotEqualValues(t, body, fakeBody)
|
||||
})
|
||||
}
|
||||
checkLinkHeaders(t, []string{"</style.css>; rel=preload; as=style", "</script.js>; rel=preload; as=script", "</foo.js>; rel=preload; as=script"}, res.Header["Link"])
|
||||
|
||||
assert.Equal(t, gzipName, res.Header.Get(contentEncodingHeader))
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
assert.NotEqualValues(t, body, fakeBody)
|
||||
}
|
||||
|
||||
func BenchmarkCompressGzip(b *testing.B) {
|
||||
|
@ -192,12 +192,17 @@ func (r *responseWriter) Header() http.Header {
|
||||
}
|
||||
|
||||
func (r *responseWriter) WriteHeader(statusCode int) {
|
||||
if r.statusCodeSet {
|
||||
// Handle informational headers
|
||||
// This is gated to not forward 1xx responses on builds prior to go1.20.
|
||||
if statusCode >= 100 && statusCode <= 199 {
|
||||
r.rw.WriteHeader(statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
r.statusCode = statusCode
|
||||
r.statusCodeSet = true
|
||||
if !r.statusCodeSet {
|
||||
r.statusCode = statusCode
|
||||
r.statusCodeSet = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *responseWriter) Write(p []byte) (int, error) {
|
||||
@ -319,11 +324,16 @@ func (r *responseWriter) Flush() {
|
||||
}
|
||||
|
||||
// Here, nothing was ever written either to rw or to bw (since we're still
|
||||
// waiting to decide whether to compress), so we do not need to flush anything.
|
||||
// Note that we diverge with klauspost's gzip behavior, where they instead
|
||||
// force compression and flush whatever was in the buffer in this case.
|
||||
// waiting to decide whether to compress), so to be aligned with klauspost's
|
||||
// gzip behavior we force the compression and flush whatever was in the buffer in this case.
|
||||
if !r.compressionStarted {
|
||||
return
|
||||
r.rw.Header().Del(contentLength)
|
||||
|
||||
r.rw.Header().Set(contentEncoding, r.compressionWriter.ContentEncoding())
|
||||
r.rw.WriteHeader(r.statusCode)
|
||||
r.headersSent = true
|
||||
|
||||
r.compressionStarted = true
|
||||
}
|
||||
|
||||
// Conversely, we here know that something was already written to bw (or is
|
||||
|
@ -498,6 +498,73 @@ func Test_FlushAfterAllWrites(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FlushForceCompress(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg Config
|
||||
algo string
|
||||
readerBuilder func(io.Reader) (io.Reader, error)
|
||||
acceptEncoding string
|
||||
}{
|
||||
{
|
||||
desc: "brotli",
|
||||
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
|
||||
algo: brotliName,
|
||||
readerBuilder: func(reader io.Reader) (io.Reader, error) {
|
||||
return brotli.NewReader(reader), nil
|
||||
},
|
||||
acceptEncoding: "br",
|
||||
},
|
||||
{
|
||||
desc: "zstd",
|
||||
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
|
||||
algo: zstdName,
|
||||
readerBuilder: func(reader io.Reader) (io.Reader, error) {
|
||||
return zstd.NewReader(reader)
|
||||
},
|
||||
acceptEncoding: "zstd",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
_, err := rw.Write(smallTestBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
rw.(http.Flusher).Flush()
|
||||
})
|
||||
|
||||
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, test.algo, next))
|
||||
defer srv.Close()
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set(acceptEncoding, test.acceptEncoding)
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode)
|
||||
assert.Equal(t, test.acceptEncoding, res.Header.Get(contentEncoding))
|
||||
|
||||
reader, err := test.readerBuilder(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := io.ReadAll(reader)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, smallTestBody, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ExcludedContentTypes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -36,6 +36,48 @@ type Listener interface {
|
||||
// each of them about a retry attempt.
|
||||
type Listeners []Listener
|
||||
|
||||
// Retried exists to implement the Listener interface. It calls Retried on each of its slice entries.
|
||||
func (l Listeners) Retried(req *http.Request, attempt int) {
|
||||
for _, listener := range l {
|
||||
listener.Retried(req, attempt)
|
||||
}
|
||||
}
|
||||
|
||||
type shouldRetryContextKey struct{}
|
||||
|
||||
// ShouldRetry is a function allowing to enable/disable the retry middleware mechanism.
|
||||
type ShouldRetry func(shouldRetry bool)
|
||||
|
||||
// ContextShouldRetry returns the ShouldRetry function if it has been set by the Retry middleware in the chain.
|
||||
func ContextShouldRetry(ctx context.Context) ShouldRetry {
|
||||
f, _ := ctx.Value(shouldRetryContextKey{}).(ShouldRetry)
|
||||
return f
|
||||
}
|
||||
|
||||
// WrapHandler wraps a given http.Handler to inject the httptrace.ClientTrace in the request context when it is needed
|
||||
// by the retry middleware.
|
||||
func WrapHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if shouldRetry := ContextShouldRetry(req.Context()); shouldRetry != nil {
|
||||
shouldRetry(true)
|
||||
|
||||
trace := &httptrace.ClientTrace{
|
||||
WroteHeaders: func() {
|
||||
shouldRetry(false)
|
||||
},
|
||||
WroteRequest: func(httptrace.WroteRequestInfo) {
|
||||
shouldRetry(false)
|
||||
},
|
||||
}
|
||||
newCtx := httptrace.WithClientTrace(req.Context(), trace)
|
||||
next.ServeHTTP(rw, req.WithContext(newCtx))
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
||||
// retry is a middleware that retries requests.
|
||||
type retry struct {
|
||||
attempts int
|
||||
@ -101,19 +143,13 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
req = req.WithContext(tracingCtx)
|
||||
}
|
||||
|
||||
shouldRetry := attempts < r.attempts
|
||||
retryResponseWriter := newResponseWriter(rw, shouldRetry)
|
||||
remainAttempts := attempts < r.attempts
|
||||
retryResponseWriter := newResponseWriter(rw)
|
||||
|
||||
// Disable retries when the backend already received request data
|
||||
clientTrace := &httptrace.ClientTrace{
|
||||
WroteHeaders: func() {
|
||||
retryResponseWriter.DisableRetries()
|
||||
},
|
||||
WroteRequest: func(httptrace.WroteRequestInfo) {
|
||||
retryResponseWriter.DisableRetries()
|
||||
},
|
||||
var shouldRetry ShouldRetry = func(shouldRetry bool) {
|
||||
retryResponseWriter.SetShouldRetry(remainAttempts && shouldRetry)
|
||||
}
|
||||
newCtx := httptrace.WithClientTrace(req.Context(), clientTrace)
|
||||
newCtx := context.WithValue(req.Context(), shouldRetryContextKey{}, shouldRetry)
|
||||
|
||||
r.next.ServeHTTP(retryResponseWriter, req.Clone(newCtx))
|
||||
|
||||
@ -164,18 +200,10 @@ func (r *retry) newBackOff() backoff.BackOff {
|
||||
return b
|
||||
}
|
||||
|
||||
// Retried exists to implement the Listener interface. It calls Retried on each of its slice entries.
|
||||
func (l Listeners) Retried(req *http.Request, attempt int) {
|
||||
for _, listener := range l {
|
||||
listener.Retried(req, attempt)
|
||||
}
|
||||
}
|
||||
|
||||
func newResponseWriter(rw http.ResponseWriter, shouldRetry bool) *responseWriter {
|
||||
func newResponseWriter(rw http.ResponseWriter) *responseWriter {
|
||||
return &responseWriter{
|
||||
responseWriter: rw,
|
||||
headers: make(http.Header),
|
||||
shouldRetry: shouldRetry,
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,8 +218,8 @@ func (r *responseWriter) ShouldRetry() bool {
|
||||
return r.shouldRetry
|
||||
}
|
||||
|
||||
func (r *responseWriter) DisableRetries() {
|
||||
r.shouldRetry = false
|
||||
func (r *responseWriter) SetShouldRetry(shouldRetry bool) {
|
||||
r.shouldRetry = shouldRetry
|
||||
}
|
||||
|
||||
func (r *responseWriter) Header() http.Header {
|
||||
@ -205,20 +233,14 @@ func (r *responseWriter) Write(buf []byte) (int, error) {
|
||||
if r.ShouldRetry() {
|
||||
return len(buf), nil
|
||||
}
|
||||
if !r.written {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
}
|
||||
return r.responseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func (r *responseWriter) WriteHeader(code int) {
|
||||
if r.ShouldRetry() && code == http.StatusServiceUnavailable {
|
||||
// We get a 503 HTTP Status Code when there is no backend server in the pool
|
||||
// to which the request could be sent. Also, note that r.ShouldRetry()
|
||||
// will never return true in case there was a connection established to
|
||||
// the backend server and so we can be sure that the 503 was produced
|
||||
// inside Traefik already and we don't have to retry in this cases.
|
||||
r.DisableRetries()
|
||||
}
|
||||
|
||||
if r.ShouldRetry() || r.written {
|
||||
if r.shouldRetry || r.written {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -105,12 +105,21 @@ func TestRetry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
retryAttempts := 0
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
// This signals that a connection will be established with the backend
|
||||
// to enable the Retry middleware mechanism.
|
||||
shouldRetry := ContextShouldRetry(req.Context())
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(true)
|
||||
}
|
||||
|
||||
retryAttempts++
|
||||
|
||||
if retryAttempts > test.amountFaultyEndpoints {
|
||||
// calls WroteHeaders on httptrace.
|
||||
_ = r.Write(io.Discard)
|
||||
// This signals that request headers have been sent to the backend.
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(false)
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
return
|
||||
@ -152,27 +161,16 @@ func TestRetryEmptyServerList(t *testing.T) {
|
||||
assert.Equal(t, 0, retryListener.timesCalled)
|
||||
}
|
||||
|
||||
func TestRetryListeners(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
retryListeners := Listeners{&countingRetryListener{}, &countingRetryListener{}}
|
||||
|
||||
retryListeners.Retried(req, 1)
|
||||
retryListeners.Retried(req, 1)
|
||||
|
||||
for _, retryListener := range retryListeners {
|
||||
listener := retryListener.(*countingRetryListener)
|
||||
if listener.timesCalled != 2 {
|
||||
t.Errorf("retry listener was called %d time(s), want %d time(s)", listener.timesCalled, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleRetriesShouldNotLooseHeaders(t *testing.T) {
|
||||
attempt := 0
|
||||
expectedHeaderName := "X-Foo-Test-2"
|
||||
expectedHeaderValue := "bar"
|
||||
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
shouldRetry := ContextShouldRetry(req.Context())
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(true)
|
||||
}
|
||||
|
||||
headerName := fmt.Sprintf("X-Foo-Test-%d", attempt)
|
||||
rw.Header().Add(headerName, expectedHeaderValue)
|
||||
if attempt < 2 {
|
||||
@ -181,43 +179,54 @@ func TestMultipleRetriesShouldNotLooseHeaders(t *testing.T) {
|
||||
}
|
||||
|
||||
// Request has been successfully written to backend
|
||||
trace := httptrace.ContextClientTrace(req.Context())
|
||||
trace.WroteHeaders()
|
||||
shouldRetry(false)
|
||||
|
||||
// And we decide to answer to client
|
||||
// And we decide to answer to client.
|
||||
rw.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
responseRecorder := httptest.NewRecorder()
|
||||
retry.ServeHTTP(responseRecorder, testhelpers.MustNewRequest(http.MethodGet, "http://test", http.NoBody))
|
||||
res := httptest.NewRecorder()
|
||||
retry.ServeHTTP(res, testhelpers.MustNewRequest(http.MethodGet, "http://test", http.NoBody))
|
||||
|
||||
headerValue := responseRecorder.Header().Get(expectedHeaderName)
|
||||
|
||||
// Validate if we have the correct header
|
||||
if headerValue != expectedHeaderValue {
|
||||
t.Errorf("Expected to have %s for header %s, got %s", expectedHeaderValue, expectedHeaderName, headerValue)
|
||||
}
|
||||
// The third header attempt is kept.
|
||||
headerValue := res.Header().Get("X-Foo-Test-2")
|
||||
assert.Equal(t, expectedHeaderValue, headerValue)
|
||||
|
||||
// Validate that we don't have headers from previous attempts
|
||||
for i := range attempt {
|
||||
headerName := fmt.Sprintf("X-Foo-Test-%d", i)
|
||||
headerValue = responseRecorder.Header().Get("headerName")
|
||||
headerValue = res.Header().Get(headerName)
|
||||
if headerValue != "" {
|
||||
t.Errorf("Expected no value for header %s, got %s", headerName, headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// countingRetryListener is a Listener implementation to count the times the Retried fn is called.
|
||||
type countingRetryListener struct {
|
||||
timesCalled int
|
||||
}
|
||||
func TestRetryShouldNotLooseHeadersOnWrite(t *testing.T) {
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Add("X-Foo-Test", "bar")
|
||||
|
||||
func (l *countingRetryListener) Retried(req *http.Request, attempt int) {
|
||||
l.timesCalled++
|
||||
// Request has been successfully written to backend.
|
||||
shouldRetry := ContextShouldRetry(req.Context())
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(false)
|
||||
}
|
||||
// And we decide to answer to client without calling WriteHeader.
|
||||
_, err := rw.Write([]byte("bar"))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
retry.ServeHTTP(res, testhelpers.MustNewRequest(http.MethodGet, "http://test", http.NoBody))
|
||||
|
||||
headerValue := res.Header().Get("X-Foo-Test")
|
||||
assert.Equal(t, "bar", headerValue)
|
||||
}
|
||||
|
||||
func TestRetryWithFlush(t *testing.T) {
|
||||
@ -275,12 +284,24 @@ func TestRetryWebsocket(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
retryAttempts := 0
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
// This signals that a connection will be established with the backend
|
||||
// to enable the Retry middleware mechanism.
|
||||
shouldRetry := ContextShouldRetry(req.Context())
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(true)
|
||||
}
|
||||
|
||||
retryAttempts++
|
||||
|
||||
if retryAttempts > test.amountFaultyEndpoints {
|
||||
// This signals that request headers have been sent to the backend.
|
||||
if shouldRetry != nil {
|
||||
shouldRetry(false)
|
||||
}
|
||||
|
||||
upgrader := websocket.Upgrader{}
|
||||
_, err := upgrader.Upgrade(rw, r, nil)
|
||||
_, err := upgrader.Upgrade(rw, req, nil)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@ -387,3 +408,12 @@ func Test1xxResponses(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 0, retryListener.timesCalled)
|
||||
}
|
||||
|
||||
// countingRetryListener is a Listener implementation to count the times the Retried fn is called.
|
||||
type countingRetryListener struct {
|
||||
timesCalled int
|
||||
}
|
||||
|
||||
func (l *countingRetryListener) Retried(req *http.Request, attempt int) {
|
||||
l.timesCalled++
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package ecs
|
||||
|
||||
import "github.com/aws/aws-sdk-go/service/ecs"
|
||||
import (
|
||||
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
|
||||
)
|
||||
|
||||
func instance(ops ...func(*ecsInstance)) ecsInstance {
|
||||
e := &ecsInstance{
|
||||
containerDefinition: &ecs.ContainerDefinition{},
|
||||
containerDefinition: &ecstypes.ContainerDefinition{},
|
||||
}
|
||||
|
||||
for _, op := range ops {
|
||||
@ -36,7 +39,7 @@ func iMachine(opts ...func(*machine)) func(*ecsInstance) {
|
||||
}
|
||||
}
|
||||
|
||||
func mState(state string) func(*machine) {
|
||||
func mState(state ec2types.InstanceStateName) func(*machine) {
|
||||
return func(m *machine) {
|
||||
m.state = state
|
||||
}
|
||||
@ -48,7 +51,7 @@ func mPrivateIP(ip string) func(*machine) {
|
||||
}
|
||||
}
|
||||
|
||||
func mHealthStatus(status string) func(*machine) {
|
||||
func mHealthStatus(status ecstypes.HealthStatus) func(*machine) {
|
||||
return func(m *machine) {
|
||||
m.healthStatus = status
|
||||
}
|
||||
@ -64,10 +67,10 @@ func mPorts(opts ...func(*portMapping)) func(*machine) {
|
||||
}
|
||||
}
|
||||
|
||||
func mPort(containerPort, hostPort int32, protocol string) func(*portMapping) {
|
||||
func mPort(containerPort, hostPort int32, protocol ecstypes.TransportProtocol) func(*portMapping) {
|
||||
return func(pm *portMapping) {
|
||||
pm.containerPort = int64(containerPort)
|
||||
pm.hostPort = int64(hostPort)
|
||||
pm.containerPort = containerPort
|
||||
pm.hostPort = hostPort
|
||||
pm.protocol = protocol
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
@ -161,12 +161,12 @@ func (p *Provider) filterInstance(ctx context.Context, instance ecsInstance) boo
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.ToLower(instance.machine.state) != ec2.InstanceStateNameRunning {
|
||||
if instance.machine.state != ec2types.InstanceStateNameRunning {
|
||||
logger.Debug().Msgf("Filtering ecs instance with an incorrect state %s (%s) (state = %s)", instance.Name, instance.ID, instance.machine.state)
|
||||
return false
|
||||
}
|
||||
|
||||
if instance.machine.healthStatus == "UNHEALTHY" {
|
||||
if instance.machine.healthStatus == ecstypes.HealthStatusUnhealthy {
|
||||
logger.Debug().Msgf("Filtering unhealthy ecs instance %s (%s)", instance.Name, instance.ID)
|
||||
return false
|
||||
}
|
||||
@ -300,9 +300,9 @@ func (p *Provider) getIPPort(instance ecsInstance, serverPort string) (string, s
|
||||
func getPort(instance ecsInstance, serverPort string) string {
|
||||
if len(serverPort) > 0 {
|
||||
for _, port := range instance.machine.ports {
|
||||
containerPort := strconv.FormatInt(port.containerPort, 10)
|
||||
containerPort := strconv.FormatInt(int64(port.containerPort), 10)
|
||||
if serverPort == containerPort {
|
||||
return strconv.FormatInt(port.hostPort, 10)
|
||||
return strconv.FormatInt(int64(port.hostPort), 10)
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +311,7 @@ func getPort(instance ecsInstance, serverPort string) string {
|
||||
|
||||
var ports []nat.Port
|
||||
for _, port := range instance.machine.ports {
|
||||
natPort, err := nat.NewPort(port.protocol, strconv.FormatInt(port.hostPort, 10))
|
||||
natPort, err := nat.NewPort(string(port.protocol), strconv.FormatInt(int64(port.hostPort), 10))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
@ -31,10 +32,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
id("1"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337, "TCP"),
|
||||
mPort(0, 1337, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -90,10 +91,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -151,10 +152,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
"traefik.domain": "foo.bar",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -210,10 +211,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -263,10 +264,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -316,10 +317,10 @@ func TestDefaultRule(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -412,10 +413,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.test": "",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -451,10 +452,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.services.test": "",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -490,10 +491,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.udp.services.test": "",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -527,10 +528,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -585,10 +586,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -596,10 +597,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test2"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -674,10 +675,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -686,10 +687,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -749,10 +750,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -811,10 +812,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.service": "Service1",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -870,10 +871,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -930,10 +931,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -991,10 +992,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service2.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1060,10 +1061,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.service": "Service1",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1120,10 +1121,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1134,10 +1135,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "false",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1180,10 +1181,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "false",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1194,10 +1195,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1208,10 +1209,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1254,10 +1255,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1268,10 +1269,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1331,10 +1332,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1398,10 +1399,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1412,10 +1413,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1482,10 +1483,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1496,10 +1497,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "41",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1560,10 +1561,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1574,10 +1575,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "41",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1588,10 +1589,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "40",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.3"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1655,10 +1656,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1669,10 +1670,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`bar.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1727,10 +1728,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1741,10 +1742,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`bar.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1755,10 +1756,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foobar.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.3"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1816,10 +1817,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1831,10 +1832,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1893,10 +1894,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1906,10 +1907,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Router1.rule": "Host(`foo.com`)",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1974,10 +1975,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.wrong.label": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2035,10 +2036,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.port": "80",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
mPort(80, 8080, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2095,7 +2096,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
@ -2156,7 +2157,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.preservepath": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
@ -2218,7 +2219,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.port": "1234",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
@ -2258,7 +2259,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.scheme": "https",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
@ -2298,10 +2299,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.LoadBalancer.server.port": "8040",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
mPort(80, 8080, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2363,11 +2364,11 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service2.LoadBalancer.server.port": "4444",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(4444, 32123, "tcp"),
|
||||
mPort(4445, 32124, "tcp"),
|
||||
mPort(4444, 32123, ecstypes.TransportProtocolTcp),
|
||||
mPort(4445, 32124, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2442,10 +2443,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service2.LoadBalancer.server.port": "8080",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2508,7 +2509,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
name("Test"),
|
||||
labels(map[string]string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(),
|
||||
),
|
||||
@ -2545,7 +2546,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.middlewares.Middleware1.inflightreq.amount": "42",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(),
|
||||
),
|
||||
@ -2582,10 +2583,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.enable": "false",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2621,11 +2622,11 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.enable": "false",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mHealthStatus("UNHEALTHY"),
|
||||
mHealthStatus(ecstypes.HealthStatusUnhealthy),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2661,10 +2662,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.enable": "false",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNamePending),
|
||||
mState(ec2types.InstanceStateNamePending),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2700,10 +2701,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tags": "foo",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2740,10 +2741,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tags": "foo",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2802,10 +2803,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.routers.Test.middlewares": "Middleware1",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2874,10 +2875,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.routers.Test.middlewares": "Middleware1",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2936,10 +2937,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.routers.foo.tls": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2991,10 +2992,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.udp.routers.foo.entrypoints": "mydns",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "udp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolUdp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3045,10 +3046,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.routers.foo.tls": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3096,10 +3097,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.services.foo.loadbalancer.server.port": "80",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
mPort(80, 8080, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3154,10 +3155,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.udp.services.foo.loadbalancer.server.port": "80",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "udp"),
|
||||
mPort(80, 8080, ecstypes.TransportProtocolUdp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3210,10 +3211,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3226,10 +3227,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3307,10 +3308,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.udp.services.foo.loadbalancer.server.port": "8080",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3357,10 +3358,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tcp.services.foo.loadbalancer.server.port": "80",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 8080, "tcp"),
|
||||
mPort(80, 8080, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -3408,10 +3409,10 @@ func Test_buildConfiguration(t *testing.T) {
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.domain.sans": "foobar, fiibar",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mState(ec2types.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 80, "tcp"),
|
||||
mPort(0, 80, ecstypes.TransportProtocolTcp),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -3,21 +3,21 @@ package ecs
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"iter"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
"github.com/aws/aws-sdk-go/service/ssm"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ecs"
|
||||
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ssm"
|
||||
ssmtypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"github.com/rs/zerolog"
|
||||
@ -50,29 +50,29 @@ type Provider struct {
|
||||
type ecsInstance struct {
|
||||
Name string
|
||||
ID string
|
||||
containerDefinition *ecs.ContainerDefinition
|
||||
containerDefinition *ecstypes.ContainerDefinition
|
||||
machine *machine
|
||||
Labels map[string]string
|
||||
ExtraConf configuration
|
||||
}
|
||||
|
||||
type portMapping struct {
|
||||
containerPort int64
|
||||
hostPort int64
|
||||
protocol string
|
||||
containerPort int32
|
||||
hostPort int32
|
||||
protocol ecstypes.TransportProtocol
|
||||
}
|
||||
|
||||
type machine struct {
|
||||
state string
|
||||
state ec2types.InstanceStateName
|
||||
privateIP string
|
||||
ports []portMapping
|
||||
healthStatus string
|
||||
healthStatus ecstypes.HealthStatus
|
||||
}
|
||||
|
||||
type awsClient struct {
|
||||
ecs *ecs.ECS
|
||||
ec2 *ec2.EC2
|
||||
ssm *ssm.SSM
|
||||
ecs *ecs.Client
|
||||
ec2 *ec2.Client
|
||||
ssm *ssm.Client
|
||||
}
|
||||
|
||||
// DefaultTemplateRule The default template for the default rule.
|
||||
@ -104,54 +104,38 @@ func (p *Provider) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) createClient(logger zerolog.Logger) (*awsClient, error) {
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
})
|
||||
func (p *Provider) createClient(ctx context.Context, logger zerolog.Logger) (*awsClient, error) {
|
||||
optFns := []func(*config.LoadOptions) error{
|
||||
config.WithLogger(logs.NewAWSWrapper(logger)),
|
||||
}
|
||||
if p.Region != "" {
|
||||
optFns = append(optFns, config.WithRegion(p.Region))
|
||||
} else {
|
||||
logger.Info().Msg("No region provided, will retrieve region from the EC2 Metadata service")
|
||||
optFns = append(optFns, config.WithEC2IMDSRegion())
|
||||
}
|
||||
|
||||
if p.AccessKeyID != "" && p.SecretAccessKey != "" {
|
||||
// From https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specify-credentials-programmatically:
|
||||
// "If you explicitly provide credentials, as in this example, the SDK uses only those credentials."
|
||||
// this makes sure that user-defined credentials always have the highest priority
|
||||
staticCreds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(p.AccessKeyID, p.SecretAccessKey, ""))
|
||||
optFns = append(optFns, config.WithCredentialsProvider(staticCreds))
|
||||
|
||||
// If the access key and secret access key are not provided, config.LoadDefaultConfig
|
||||
// will look for the credentials in the default credential chain.
|
||||
// See https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials.
|
||||
}
|
||||
|
||||
cfg, err := config.LoadDefaultConfig(ctx, optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ec2meta := ec2metadata.New(sess)
|
||||
if p.Region == "" && ec2meta.Available() {
|
||||
logger.Info().Msg("No region provided, querying instance metadata endpoint...")
|
||||
identity, err := ec2meta.GetInstanceIdentityDocument()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Region = identity.Region
|
||||
}
|
||||
|
||||
cfg := aws.NewConfig().
|
||||
WithCredentials(credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.StaticProvider{
|
||||
Value: credentials.Value{
|
||||
AccessKeyID: p.AccessKeyID,
|
||||
SecretAccessKey: p.SecretAccessKey,
|
||||
},
|
||||
},
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{},
|
||||
defaults.RemoteCredProvider(*(defaults.Config()), defaults.Handlers()),
|
||||
stscreds.NewWebIdentityRoleProviderWithOptions(
|
||||
sts.New(sess),
|
||||
os.Getenv("AWS_ROLE_ARN"),
|
||||
"",
|
||||
stscreds.FetchTokenPath(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")),
|
||||
),
|
||||
}))
|
||||
|
||||
// Set the region if it is defined by the user or resolved from the EC2 metadata.
|
||||
if p.Region != "" {
|
||||
cfg.Region = &p.Region
|
||||
}
|
||||
|
||||
cfg.WithLogger(logs.NewAWSWrapper(logger))
|
||||
|
||||
return &awsClient{
|
||||
ecs.New(sess, cfg),
|
||||
ec2.New(sess, cfg),
|
||||
ssm.New(sess, cfg),
|
||||
ecs.NewFromConfig(cfg),
|
||||
ec2.NewFromConfig(cfg),
|
||||
ssm.NewFromConfig(cfg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -162,7 +146,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
||||
ctxLog := logger.WithContext(routineCtx)
|
||||
|
||||
operation := func() error {
|
||||
awsClient, err := p.createClient(logger)
|
||||
awsClient, err := p.createClient(ctxLog, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create AWS client: %w", err)
|
||||
}
|
||||
@ -220,28 +204,19 @@ func (p *Provider) loadConfiguration(ctx context.Context, client *awsClient, con
|
||||
func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsInstance, error) {
|
||||
logger := log.Ctx(ctx)
|
||||
|
||||
var clustersArn []*string
|
||||
var clusters []string
|
||||
|
||||
if p.AutoDiscoverClusters {
|
||||
input := &ecs.ListClustersInput{}
|
||||
for {
|
||||
result, err := client.ecs.ListClusters(input)
|
||||
|
||||
paginator := ecs.NewListClustersPaginator(client.ecs, input)
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result != nil {
|
||||
clustersArn = append(clustersArn, result.ClusterArns...)
|
||||
input.NextToken = result.NextToken
|
||||
if result.NextToken == nil {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, cArn := range clustersArn {
|
||||
clusters = append(clusters, *cArn)
|
||||
|
||||
clusters = append(clusters, page.ClusterArns...)
|
||||
}
|
||||
} else {
|
||||
clusters = p.Clusters
|
||||
@ -253,13 +228,19 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
for _, c := range clusters {
|
||||
input := &ecs.ListTasksInput{
|
||||
Cluster: &c,
|
||||
DesiredStatus: aws.String(ecs.DesiredStatusRunning),
|
||||
DesiredStatus: ecstypes.DesiredStatusRunning,
|
||||
}
|
||||
|
||||
tasks := make(map[string]*ecs.Task)
|
||||
err := client.ecs.ListTasksPagesWithContext(ctx, input, func(page *ecs.ListTasksOutput, lastPage bool) bool {
|
||||
tasks := make(map[string]ecstypes.Task)
|
||||
|
||||
paginator := ecs.NewListTasksPaginator(client.ecs, input)
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing tasks: %w", err)
|
||||
}
|
||||
if len(page.TaskArns) > 0 {
|
||||
resp, err := client.ecs.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
|
||||
resp, err := client.ecs.DescribeTasks(ctx, &ecs.DescribeTasksInput{
|
||||
Tasks: page.TaskArns,
|
||||
Cluster: &c,
|
||||
})
|
||||
@ -267,19 +248,15 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
logger.Error().Msgf("Unable to describe tasks for %v", page.TaskArns)
|
||||
} else {
|
||||
for _, t := range resp.Tasks {
|
||||
if p.HealthyTasksOnly && aws.StringValue(t.HealthStatus) != ecs.HealthStatusHealthy {
|
||||
logger.Debug().Msgf("Skipping unhealthy task %s", aws.StringValue(t.TaskArn))
|
||||
if p.HealthyTasksOnly && t.HealthStatus != ecstypes.HealthStatusHealthy {
|
||||
logger.Debug().Msgf("Skipping unhealthy task %s", aws.ToString(t.TaskArn))
|
||||
continue
|
||||
}
|
||||
|
||||
tasks[aws.StringValue(t.TaskArn)] = t
|
||||
tasks[aws.ToString(t.TaskArn)] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
return !lastPage
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing tasks: %w", err)
|
||||
}
|
||||
|
||||
// Skip to the next cluster if there are no tasks found on
|
||||
@ -293,7 +270,7 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
return nil, err
|
||||
}
|
||||
|
||||
miInstances := make(map[string]*ssm.InstanceInformation)
|
||||
miInstances := make(map[string]ssmtypes.InstanceInformation)
|
||||
if p.ECSAnywhere {
|
||||
// Try looking up for instances on ECS Anywhere
|
||||
miInstances, err = p.lookupMiInstances(ctx, client, &c, tasks)
|
||||
@ -308,74 +285,67 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
}
|
||||
|
||||
for key, task := range tasks {
|
||||
containerInstance := ec2Instances[aws.StringValue(task.ContainerInstanceArn)]
|
||||
containerInstance, hasContainerInstance := ec2Instances[aws.ToString(task.ContainerInstanceArn)]
|
||||
taskDef := taskDefinitions[key]
|
||||
|
||||
for _, container := range task.Containers {
|
||||
var containerDefinition *ecs.ContainerDefinition
|
||||
var containerDefinition *ecstypes.ContainerDefinition
|
||||
for _, def := range taskDef.ContainerDefinitions {
|
||||
if aws.StringValue(container.Name) == aws.StringValue(def.Name) {
|
||||
containerDefinition = def
|
||||
if aws.ToString(container.Name) == aws.ToString(def.Name) {
|
||||
containerDefinition = &def
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if containerDefinition == nil {
|
||||
logger.Debug().Msgf("Unable to find container definition for %s", aws.StringValue(container.Name))
|
||||
logger.Debug().Msgf("Unable to find container definition for %s", aws.ToString(container.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
var mach *machine
|
||||
if aws.StringValue(taskDef.NetworkMode) == "awsvpc" && len(task.Attachments) != 0 {
|
||||
if taskDef.NetworkMode == ecstypes.NetworkModeAwsvpc && len(task.Attachments) != 0 {
|
||||
if len(container.NetworkInterfaces) == 0 {
|
||||
logger.Error().Msgf("Skip container %s: no network interfaces", aws.StringValue(container.Name))
|
||||
logger.Error().Msgf("Skip container %s: no network interfaces", aws.ToString(container.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
var ports []portMapping
|
||||
for _, mapping := range containerDefinition.PortMappings {
|
||||
if mapping != nil {
|
||||
protocol := "TCP"
|
||||
if aws.StringValue(mapping.Protocol) == "udp" {
|
||||
protocol = "UDP"
|
||||
}
|
||||
|
||||
ports = append(ports, portMapping{
|
||||
hostPort: aws.Int64Value(mapping.HostPort),
|
||||
containerPort: aws.Int64Value(mapping.ContainerPort),
|
||||
protocol: protocol,
|
||||
})
|
||||
}
|
||||
ports = append(ports, portMapping{
|
||||
hostPort: aws.ToInt32(mapping.HostPort),
|
||||
containerPort: aws.ToInt32(mapping.ContainerPort),
|
||||
protocol: mapping.Protocol,
|
||||
})
|
||||
}
|
||||
mach = &machine{
|
||||
privateIP: aws.StringValue(container.NetworkInterfaces[0].PrivateIpv4Address),
|
||||
privateIP: aws.ToString(container.NetworkInterfaces[0].PrivateIpv4Address),
|
||||
ports: ports,
|
||||
state: aws.StringValue(task.LastStatus),
|
||||
healthStatus: aws.StringValue(task.HealthStatus),
|
||||
state: ec2types.InstanceStateName(strings.ToLower(aws.ToString(task.LastStatus))),
|
||||
healthStatus: task.HealthStatus,
|
||||
}
|
||||
} else {
|
||||
miContainerInstance := miInstances[aws.StringValue(task.ContainerInstanceArn)]
|
||||
if containerInstance == nil && miContainerInstance == nil {
|
||||
logger.Error().Msgf("Unable to find container instance information for %s", aws.StringValue(container.Name))
|
||||
miContainerInstance, hasMiContainerInstance := miInstances[aws.ToString(task.ContainerInstanceArn)]
|
||||
if !hasContainerInstance && !hasMiContainerInstance {
|
||||
logger.Error().Msgf("Unable to find container instance information for %s", aws.ToString(container.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
var ports []portMapping
|
||||
for _, mapping := range container.NetworkBindings {
|
||||
if mapping != nil {
|
||||
ports = append(ports, portMapping{
|
||||
hostPort: aws.Int64Value(mapping.HostPort),
|
||||
containerPort: aws.Int64Value(mapping.ContainerPort),
|
||||
})
|
||||
}
|
||||
ports = append(ports, portMapping{
|
||||
hostPort: aws.ToInt32(mapping.HostPort),
|
||||
containerPort: aws.ToInt32(mapping.ContainerPort),
|
||||
protocol: mapping.Protocol,
|
||||
})
|
||||
}
|
||||
var privateIPAddress, stateName string
|
||||
if containerInstance != nil {
|
||||
privateIPAddress = aws.StringValue(containerInstance.PrivateIpAddress)
|
||||
stateName = aws.StringValue(containerInstance.State.Name)
|
||||
} else if miContainerInstance != nil {
|
||||
privateIPAddress = aws.StringValue(miContainerInstance.IPAddress)
|
||||
stateName = aws.StringValue(task.LastStatus)
|
||||
var privateIPAddress string
|
||||
var stateName ec2types.InstanceStateName
|
||||
if hasContainerInstance {
|
||||
privateIPAddress = aws.ToString(containerInstance.PrivateIpAddress)
|
||||
stateName = containerInstance.State.Name
|
||||
} else if hasMiContainerInstance {
|
||||
privateIPAddress = aws.ToString(miContainerInstance.IPAddress)
|
||||
stateName = ec2types.InstanceStateName(strings.ToLower(aws.ToString(task.LastStatus)))
|
||||
}
|
||||
|
||||
mach = &machine{
|
||||
@ -386,11 +356,11 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
}
|
||||
|
||||
instance := ecsInstance{
|
||||
Name: fmt.Sprintf("%s-%s", strings.Replace(aws.StringValue(task.Group), ":", "-", 1), *container.Name),
|
||||
Name: fmt.Sprintf("%s-%s", strings.Replace(aws.ToString(task.Group), ":", "-", 1), aws.ToString(container.Name)),
|
||||
ID: key[len(key)-12:],
|
||||
containerDefinition: containerDefinition,
|
||||
machine: mach,
|
||||
Labels: aws.StringValueMap(containerDefinition.DockerLabels),
|
||||
Labels: containerDefinition.DockerLabels,
|
||||
}
|
||||
|
||||
extraConf, err := p.getConfiguration(instance)
|
||||
@ -408,21 +378,21 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func (p *Provider) lookupMiInstances(ctx context.Context, client *awsClient, clusterName *string, ecsDatas map[string]*ecs.Task) (map[string]*ssm.InstanceInformation, error) {
|
||||
func (p *Provider) lookupMiInstances(ctx context.Context, client *awsClient, clusterName *string, ecsDatas map[string]ecstypes.Task) (map[string]ssmtypes.InstanceInformation, error) {
|
||||
instanceIDs := make(map[string]string)
|
||||
miInstances := make(map[string]*ssm.InstanceInformation)
|
||||
miInstances := make(map[string]ssmtypes.InstanceInformation)
|
||||
|
||||
var containerInstancesArns []*string
|
||||
var instanceArns []*string
|
||||
var containerInstancesArns []string
|
||||
var instanceArns []string
|
||||
|
||||
for _, task := range ecsDatas {
|
||||
if task.ContainerInstanceArn != nil {
|
||||
containerInstancesArns = append(containerInstancesArns, task.ContainerInstanceArn)
|
||||
containerInstancesArns = append(containerInstancesArns, *task.ContainerInstanceArn)
|
||||
}
|
||||
}
|
||||
|
||||
for _, arns := range p.chunkIDs(containerInstancesArns) {
|
||||
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
for arns := range chunkIDs(containerInstancesArns) {
|
||||
resp, err := client.ecs.DescribeContainerInstances(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: arns,
|
||||
Cluster: clusterName,
|
||||
})
|
||||
@ -431,23 +401,21 @@ func (p *Provider) lookupMiInstances(ctx context.Context, client *awsClient, clu
|
||||
}
|
||||
|
||||
for _, container := range resp.ContainerInstances {
|
||||
instanceIDs[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
||||
instanceIDs[aws.ToString(container.Ec2InstanceId)] = aws.ToString(container.ContainerInstanceArn)
|
||||
|
||||
// Disallow EC2 Instance IDs
|
||||
// This prevents considering EC2 instances in ECS
|
||||
// and getting InvalidInstanceID.Malformed error when calling the describe-instances endpoint.
|
||||
if !strings.HasPrefix(aws.StringValue(container.Ec2InstanceId), "mi-") {
|
||||
continue
|
||||
if strings.HasPrefix(aws.ToString(container.Ec2InstanceId), "mi-") {
|
||||
instanceArns = append(instanceArns, *container.Ec2InstanceId)
|
||||
}
|
||||
|
||||
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(instanceArns) > 0 {
|
||||
for _, ids := range p.chunkIDs(instanceArns) {
|
||||
for ids := range chunkIDs(instanceArns) {
|
||||
input := &ssm.DescribeInstanceInformationInput{
|
||||
Filters: []*ssm.InstanceInformationStringFilter{
|
||||
Filters: []ssmtypes.InstanceInformationStringFilter{
|
||||
{
|
||||
Key: aws.String("InstanceIds"),
|
||||
Values: ids,
|
||||
@ -455,18 +423,18 @@ func (p *Provider) lookupMiInstances(ctx context.Context, client *awsClient, clu
|
||||
},
|
||||
}
|
||||
|
||||
err := client.ssm.DescribeInstanceInformationPagesWithContext(ctx, input, func(page *ssm.DescribeInstanceInformationOutput, lastPage bool) bool {
|
||||
if len(page.InstanceInformationList) > 0 {
|
||||
for _, i := range page.InstanceInformationList {
|
||||
if i.InstanceId != nil {
|
||||
miInstances[instanceIDs[aws.StringValue(i.InstanceId)]] = i
|
||||
}
|
||||
paginator := ssm.NewDescribeInstanceInformationPaginator(client.ssm, input)
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("describing instances: %w", err)
|
||||
}
|
||||
|
||||
for _, i := range page.InstanceInformationList {
|
||||
if i.InstanceId != nil {
|
||||
miInstances[instanceIDs[aws.ToString(i.InstanceId)]] = i
|
||||
}
|
||||
}
|
||||
return !lastPage
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("describing instances: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -474,21 +442,21 @@ func (p *Provider) lookupMiInstances(ctx context.Context, client *awsClient, clu
|
||||
return miInstances, nil
|
||||
}
|
||||
|
||||
func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, clusterName *string, ecsDatas map[string]*ecs.Task) (map[string]*ec2.Instance, error) {
|
||||
func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, clusterName *string, ecsDatas map[string]ecstypes.Task) (map[string]ec2types.Instance, error) {
|
||||
instanceIDs := make(map[string]string)
|
||||
ec2Instances := make(map[string]*ec2.Instance)
|
||||
ec2Instances := make(map[string]ec2types.Instance)
|
||||
|
||||
var containerInstancesArns []*string
|
||||
var instanceArns []*string
|
||||
var containerInstancesArns []string
|
||||
var instanceArns []string
|
||||
|
||||
for _, task := range ecsDatas {
|
||||
if task.ContainerInstanceArn != nil {
|
||||
containerInstancesArns = append(containerInstancesArns, task.ContainerInstanceArn)
|
||||
containerInstancesArns = append(containerInstancesArns, *task.ContainerInstanceArn)
|
||||
}
|
||||
}
|
||||
|
||||
for _, arns := range p.chunkIDs(containerInstancesArns) {
|
||||
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
for arns := range chunkIDs(containerInstancesArns) {
|
||||
resp, err := client.ecs.DescribeContainerInstances(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: arns,
|
||||
Cluster: clusterName,
|
||||
})
|
||||
@ -497,38 +465,38 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
|
||||
}
|
||||
|
||||
for _, container := range resp.ContainerInstances {
|
||||
instanceIDs[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
||||
instanceIDs[aws.ToString(container.Ec2InstanceId)] = aws.ToString(container.ContainerInstanceArn)
|
||||
// Disallow Instance IDs of the form mi-*
|
||||
// This prevents considering external instances in ECS Anywhere setups
|
||||
// and getting InvalidInstanceID.Malformed error when calling the describe-instances endpoint.
|
||||
if strings.HasPrefix(aws.StringValue(container.Ec2InstanceId), "mi-") {
|
||||
if strings.HasPrefix(aws.ToString(container.Ec2InstanceId), "mi-") {
|
||||
continue
|
||||
}
|
||||
|
||||
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
||||
if container.Ec2InstanceId != nil {
|
||||
instanceArns = append(instanceArns, *container.Ec2InstanceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(instanceArns) > 0 {
|
||||
for _, ids := range p.chunkIDs(instanceArns) {
|
||||
for ids := range chunkIDs(instanceArns) {
|
||||
input := &ec2.DescribeInstancesInput{
|
||||
InstanceIds: ids,
|
||||
}
|
||||
|
||||
err := client.ec2.DescribeInstancesPagesWithContext(ctx, input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
|
||||
if len(page.Reservations) > 0 {
|
||||
for _, r := range page.Reservations {
|
||||
for _, i := range r.Instances {
|
||||
if i.InstanceId != nil {
|
||||
ec2Instances[instanceIDs[aws.StringValue(i.InstanceId)]] = i
|
||||
}
|
||||
paginator := ec2.NewDescribeInstancesPaginator(client.ec2, input)
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("describing instances: %w", err)
|
||||
}
|
||||
for _, r := range page.Reservations {
|
||||
for _, i := range r.Instances {
|
||||
if i.InstanceId != nil {
|
||||
ec2Instances[instanceIDs[aws.ToString(i.InstanceId)]] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return !lastPage
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("describing instances: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -536,16 +504,16 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
|
||||
return ec2Instances, nil
|
||||
}
|
||||
|
||||
func (p *Provider) lookupTaskDefinitions(ctx context.Context, client *awsClient, taskDefArns map[string]*ecs.Task) (map[string]*ecs.TaskDefinition, error) {
|
||||
func (p *Provider) lookupTaskDefinitions(ctx context.Context, client *awsClient, taskDefArns map[string]ecstypes.Task) (map[string]*ecstypes.TaskDefinition, error) {
|
||||
logger := log.Ctx(ctx)
|
||||
taskDef := make(map[string]*ecs.TaskDefinition)
|
||||
taskDef := make(map[string]*ecstypes.TaskDefinition)
|
||||
|
||||
for arn, task := range taskDefArns {
|
||||
if definition, ok := existingTaskDefCache.Get(arn); ok {
|
||||
taskDef[arn] = definition.(*ecs.TaskDefinition)
|
||||
taskDef[arn] = definition.(*ecstypes.TaskDefinition)
|
||||
logger.Debug().Msgf("Found cached task definition for %s. Skipping the call", arn)
|
||||
} else {
|
||||
resp, err := client.ecs.DescribeTaskDefinitionWithContext(ctx, &ecs.DescribeTaskDefinitionInput{
|
||||
resp, err := client.ecs.DescribeTaskDefinition(ctx, &ecs.DescribeTaskDefinitionInput{
|
||||
TaskDefinition: task.TaskDefinitionArn,
|
||||
})
|
||||
if err != nil {
|
||||
@ -561,16 +529,6 @@ func (p *Provider) lookupTaskDefinitions(ctx context.Context, client *awsClient,
|
||||
|
||||
// chunkIDs ECS expects no more than 100 parameters be passed to a API call;
|
||||
// thus, pack each string into an array capped at 100 elements.
|
||||
func (p *Provider) chunkIDs(ids []*string) [][]*string {
|
||||
var chunked [][]*string
|
||||
for i := 0; i < len(ids); i += 100 {
|
||||
var sliceEnd int
|
||||
if i+100 < len(ids) {
|
||||
sliceEnd = i + 100
|
||||
} else {
|
||||
sliceEnd = len(ids)
|
||||
}
|
||||
chunked = append(chunked, ids[i:sliceEnd])
|
||||
}
|
||||
return chunked
|
||||
func chunkIDs(ids []string) iter.Seq[[]string] {
|
||||
return slices.Chunk(ids, 100)
|
||||
}
|
||||
|
@ -3,13 +3,10 @@ package ecs
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestChunkIDs(t *testing.T) {
|
||||
provider := &Provider{}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
count int
|
||||
@ -71,13 +68,13 @@ func TestChunkIDs(t *testing.T) {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var IDs []*string
|
||||
var IDs []string
|
||||
for range test.count {
|
||||
IDs = append(IDs, aws.String("a"))
|
||||
IDs = append(IDs, "a")
|
||||
}
|
||||
|
||||
var outCount []int
|
||||
for _, el := range provider.chunkIDs(IDs) {
|
||||
for el := range chunkIDs(IDs) {
|
||||
outCount = append(outCount, len(el))
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,9 @@ func (p *Provider) loadWRRService(ctx context.Context, listener gatewayListener,
|
||||
svcName, errCondition := p.loadService(ctx, listener, conf, route, backendRef)
|
||||
weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1)))
|
||||
if errCondition != nil {
|
||||
log.Ctx(ctx).Error().
|
||||
Msgf("Unable to load HTTPRoute backend: %s", errCondition.Message)
|
||||
|
||||
condition = errCondition
|
||||
wrr.Services = append(wrr.Services, dynamic.WRRService{
|
||||
Name: svcName,
|
||||
@ -272,92 +275,14 @@ func (p *Provider) loadService(ctx context.Context, listener gatewayListener, co
|
||||
portStr := strconv.FormatInt(int64(port), 10)
|
||||
serviceName = provider.Normalize(serviceName + "-" + portStr)
|
||||
|
||||
lb, svcPort, errCondition := p.loadHTTPServers(namespace, route, backendRef)
|
||||
lb, st, errCondition := p.loadHTTPServers(ctx, namespace, route, backendRef, listener)
|
||||
if errCondition != nil {
|
||||
return serviceName, errCondition
|
||||
}
|
||||
|
||||
if !p.ExperimentalChannel {
|
||||
conf.HTTP.Services[serviceName] = &dynamic.Service{LoadBalancer: lb}
|
||||
|
||||
return serviceName, nil
|
||||
}
|
||||
|
||||
servicePolicies, err := p.client.ListBackendTLSPoliciesForService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return serviceName, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot list BackendTLSPolicies for Service %s/%s: %s", namespace, string(backendRef.Name), err),
|
||||
}
|
||||
}
|
||||
|
||||
var matchedPolicy *gatev1alpha3.BackendTLSPolicy
|
||||
for _, policy := range servicePolicies {
|
||||
matched := false
|
||||
for _, targetRef := range policy.Spec.TargetRefs {
|
||||
if targetRef.SectionName == nil || svcPort.Name == string(*targetRef.SectionName) {
|
||||
matchedPolicy = policy
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the policy targets the service, but doesn't match any port.
|
||||
if !matched {
|
||||
// update policy status
|
||||
status := gatev1alpha2.PolicyStatus{
|
||||
Ancestors: []gatev1alpha2.PolicyAncestorStatus{{
|
||||
AncestorRef: gatev1alpha2.ParentReference{
|
||||
Group: ptr.To(gatev1.Group(groupGateway)),
|
||||
Kind: ptr.To(gatev1.Kind(kindGateway)),
|
||||
Namespace: ptr.To(gatev1.Namespace(namespace)),
|
||||
Name: gatev1.ObjectName(listener.GWName),
|
||||
SectionName: ptr.To(gatev1.SectionName(listener.Name)),
|
||||
},
|
||||
ControllerName: controllerName,
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonBackendNotFound),
|
||||
Message: fmt.Sprintf("BackendTLSPolicy has no valid TargetRef for Service %s/%s", namespace, string(backendRef.Name)),
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
if err := p.client.UpdateBackendTLSPolicyStatus(ctx, ktypes.NamespacedName{Namespace: policy.Namespace, Name: policy.Name}, status); err != nil {
|
||||
logger := log.Ctx(ctx).With().
|
||||
Str("http_route", route.Name).
|
||||
Str("namespace", route.Namespace).Logger()
|
||||
logger.Warn().
|
||||
Err(err).
|
||||
Msg("Unable to update TLSRoute status")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matchedPolicy != nil {
|
||||
st, err := p.loadServersTransport(namespace, *matchedPolicy)
|
||||
if err != nil {
|
||||
return serviceName, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot apply BackendTLSPolicy for Service %s/%s: %s", namespace, string(backendRef.Name), err),
|
||||
}
|
||||
}
|
||||
|
||||
if st != nil {
|
||||
lb.ServersTransport = serviceName
|
||||
conf.HTTP.ServersTransports[serviceName] = st
|
||||
}
|
||||
if st != nil {
|
||||
lb.ServersTransport = serviceName
|
||||
conf.HTTP.ServersTransports[serviceName] = st
|
||||
}
|
||||
|
||||
conf.HTTP.Services[serviceName] = &dynamic.Service{LoadBalancer: lb}
|
||||
@ -473,10 +398,10 @@ func (p *Provider) loadHTTPRouteFilterExtensionRef(namespace string, extensionRe
|
||||
return filterFunc(string(extensionRef.Name), namespace)
|
||||
}
|
||||
|
||||
func (p *Provider) loadHTTPServers(namespace string, route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef) (*dynamic.ServersLoadBalancer, corev1.ServicePort, *metav1.Condition) {
|
||||
func (p *Provider) loadHTTPServers(ctx context.Context, namespace string, route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef, listener gatewayListener) (*dynamic.ServersLoadBalancer, *dynamic.ServersTransport, *metav1.Condition) {
|
||||
backendAddresses, svcPort, err := p.getBackendAddresses(namespace, backendRef.BackendRef)
|
||||
if err != nil {
|
||||
return nil, corev1.ServicePort{}, &metav1.Condition{
|
||||
return nil, nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
@ -486,27 +411,104 @@ func (p *Provider) loadHTTPServers(namespace string, route *gatev1.HTTPRoute, ba
|
||||
}
|
||||
}
|
||||
|
||||
protocol, err := getHTTPServiceProtocol(svcPort)
|
||||
if err != nil {
|
||||
return nil, corev1.ServicePort{}, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonUnsupportedProtocol),
|
||||
Message: fmt.Sprintf("Cannot load HTTPBackendRef %s/%s: %s", namespace, backendRef.Name, err),
|
||||
var st *dynamic.ServersTransport
|
||||
var protocol string
|
||||
if p.ExperimentalChannel {
|
||||
servicePolicies, err := p.client.ListBackendTLSPoliciesForService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return nil, nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot list BackendTLSPolicies for Service %s/%s: %s", namespace, string(backendRef.Name), err),
|
||||
}
|
||||
}
|
||||
|
||||
var matchedPolicy *gatev1alpha3.BackendTLSPolicy
|
||||
for _, policy := range servicePolicies {
|
||||
matched := false
|
||||
for _, targetRef := range policy.Spec.TargetRefs {
|
||||
if targetRef.SectionName == nil || svcPort.Name == string(*targetRef.SectionName) {
|
||||
matchedPolicy = policy
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the policy targets the service, but doesn't match any port.
|
||||
if !matched {
|
||||
// update policy status
|
||||
status := gatev1alpha2.PolicyStatus{
|
||||
Ancestors: []gatev1alpha2.PolicyAncestorStatus{{
|
||||
AncestorRef: gatev1alpha2.ParentReference{
|
||||
Group: ptr.To(gatev1.Group(groupGateway)),
|
||||
Kind: ptr.To(gatev1.Kind(kindGateway)),
|
||||
Namespace: ptr.To(gatev1.Namespace(namespace)),
|
||||
Name: gatev1.ObjectName(listener.GWName),
|
||||
SectionName: ptr.To(gatev1.SectionName(listener.Name)),
|
||||
},
|
||||
ControllerName: controllerName,
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonBackendNotFound),
|
||||
Message: fmt.Sprintf("BackendTLSPolicy has no valid TargetRef for Service %s/%s", namespace, string(backendRef.Name)),
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
if err := p.client.UpdateBackendTLSPolicyStatus(ctx, ktypes.NamespacedName{Namespace: policy.Namespace, Name: policy.Name}, status); err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).
|
||||
Msg("Unable to update BackendTLSPolicy status")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matchedPolicy != nil {
|
||||
st, err = p.loadServersTransport(namespace, *matchedPolicy)
|
||||
if err != nil {
|
||||
return nil, nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot apply BackendTLSPolicy for Service %s/%s: %s", namespace, string(backendRef.Name), err),
|
||||
}
|
||||
}
|
||||
// A backend TLS policy has been found for the service, a serversTransport configuration has been created, use/force HTTPS.
|
||||
protocol = "https"
|
||||
}
|
||||
}
|
||||
|
||||
lb := &dynamic.ServersLoadBalancer{}
|
||||
lb.SetDefaults()
|
||||
|
||||
// Guess the protocol from the service port if not set by the backend TLS policy
|
||||
if protocol == "" {
|
||||
protocol, err = getHTTPServiceProtocol(svcPort)
|
||||
if err != nil {
|
||||
return nil, nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonUnsupportedProtocol),
|
||||
Message: fmt.Sprintf("Cannot load HTTPBackendRef %s/%s: %s", namespace, backendRef.Name, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ba := range backendAddresses {
|
||||
lb.Servers = append(lb.Servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(ba.IP, strconv.Itoa(int(ba.Port)))),
|
||||
})
|
||||
}
|
||||
return lb, svcPort, nil
|
||||
return lb, st, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadServersTransport(namespace string, policy gatev1alpha3.BackendTLSPolicy) (*dynamic.ServersTransport, error) {
|
||||
|
@ -2309,10 +2309,10 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: ptr.To(true),
|
||||
@ -2381,10 +2381,10 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||
Strategy: dynamic.BalancerStrategyWRR,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
URL: "https://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
URL: "https://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: ptr.To(true),
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
||||
metricsMiddle "github.com/traefik/traefik/v3/pkg/middlewares/metrics"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/retry"
|
||||
"github.com/traefik/traefik/v3/pkg/proxy/httputil"
|
||||
"github.com/traefik/traefik/v3/pkg/safe"
|
||||
"github.com/traefik/traefik/v3/pkg/server/cookie"
|
||||
@ -368,6 +369,10 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error building proxy for server URL %s: %w", server.URL, err)
|
||||
}
|
||||
// The retry wrapping must be done just before the proxy handler,
|
||||
// to make sure that the retry will not be triggered/disabled by
|
||||
// middlewares in the chain.
|
||||
proxy = retry.WrapHandler(proxy)
|
||||
|
||||
// Prevents from enabling observability for internal resources.
|
||||
|
||||
|
@ -151,7 +151,7 @@ func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanS
|
||||
|
||||
spanCtx, span := t.Tracer.Start(ctx, spanName, opts...)
|
||||
|
||||
wrappedSpan := &Span{Span: span, tracerProvider: &TracerProvider{tracer: t}}
|
||||
wrappedSpan := &Span{Span: span, tracerProvider: &TracerProvider{TracerProvider: span.TracerProvider(), tracer: t}}
|
||||
|
||||
return trace.ContextWithSpan(spanCtx, wrappedSpan), wrappedSpan
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package tracing
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -392,3 +393,25 @@ func TestTracing(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestTracerProvider ensures that Tracer returns a valid TracerProvider
|
||||
// when using the default Traefik Tracer and a custom one.
|
||||
func TestTracerProvider(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
otlpConfig := &types.OTelTracing{}
|
||||
otlpConfig.SetDefaults()
|
||||
|
||||
config := &static.Tracing{OTLP: otlpConfig}
|
||||
tracer, closer, err := NewTracing(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
closer.Close()
|
||||
|
||||
_, span := tracer.Start(context.Background(), "test")
|
||||
defer span.End()
|
||||
|
||||
span.TracerProvider().Tracer("github.com/traefik/traefik")
|
||||
span.TracerProvider().Tracer("other")
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2046
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
export PROJECT_MODULE="github.com/traefik/traefik"
|
||||
export MODULE_VERSION="v3"
|
||||
IMAGE_NAME="kubernetes-codegen:latest"
|
||||
CURRENT_DIR="$(pwd)"
|
||||
|
||||
echo "Building codegen Docker image..."
|
||||
docker build --build-arg KUBE_VERSION=v0.29.8 \
|
||||
--build-arg USER="${USER}" \
|
||||
--build-arg UID="$(id -u)" \
|
||||
--build-arg GID="$(id -g)" \
|
||||
-f "./script/codegen.Dockerfile" \
|
||||
-t "${IMAGE_NAME}" \
|
||||
"."
|
||||
|
||||
echo "Generating Traefik clientSet code and DeepCopy code ..."
|
||||
docker run --rm \
|
||||
-v "${CURRENT_DIR}:/go/src/${PROJECT_MODULE}" \
|
||||
-w "/go/src/${PROJECT_MODULE}" \
|
||||
-e "PROJECT_MODULE=${PROJECT_MODULE}" \
|
||||
-e "MODULE_VERSION=${MODULE_VERSION}" \
|
||||
"${IMAGE_NAME}" \
|
||||
bash ./script/code-gen.sh
|
||||
|
||||
echo "Generating the CRD definitions for the documentation ..."
|
||||
docker run --rm \
|
||||
-v "${CURRENT_DIR}:/go/src/${PROJECT_MODULE}" \
|
||||
-w "/go/src/${PROJECT_MODULE}" \
|
||||
"${IMAGE_NAME}" \
|
||||
controller-gen crd:crdVersions=v1 \
|
||||
paths={./pkg/provider/kubernetes/crd/traefikio/v1alpha1/...} \
|
||||
output:dir=./docs/content/reference/dynamic-configuration/
|
||||
|
||||
echo "Concatenate the CRD definitions for publication and integration tests ..."
|
||||
cat "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/traefik.io_*.yaml > "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
|
||||
cp -f "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml "${CURRENT_DIR}"/integration/fixtures/k8s/01-traefik-crd.yml
|
@ -2,30 +2,35 @@
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
PROJECT_MODULE="github.com/traefik/traefik"
|
||||
MODULE_VERSION="v3"
|
||||
KUBE_VERSION=v0.30.10
|
||||
CURRENT_DIR="$(pwd)"
|
||||
|
||||
go install "k8s.io/code-generator/cmd/deepcopy-gen@${KUBE_VERSION}"
|
||||
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.1
|
||||
|
||||
CODEGEN_PKG="$(go env GOPATH)/pkg/mod/k8s.io/code-generator@${KUBE_VERSION}"
|
||||
# shellcheck disable=SC1091 # Cannot check source of this file
|
||||
source /go/src/k8s.io/code-generator/kube_codegen.sh
|
||||
|
||||
git config --global --add safe.directory "/go/src/${PROJECT_MODULE}"
|
||||
|
||||
rm -rf "/go/src/${PROJECT_MODULE}/${MODULE_VERSION}"
|
||||
mkdir -p "/go/src/${PROJECT_MODULE}/${MODULE_VERSION}/"
|
||||
|
||||
# TODO: remove the workaround when the issue is solved in the code-generator
|
||||
# (https://github.com/kubernetes/code-generator/issues/165).
|
||||
# Here, we create the soft link named "${PROJECT_MODULE}" to the parent directory of
|
||||
# Traefik to ensure the layout required by the kube_codegen.sh script.
|
||||
ln -s "/go/src/${PROJECT_MODULE}/pkg" "/go/src/${PROJECT_MODULE}/${MODULE_VERSION}/"
|
||||
source "${CODEGEN_PKG}/kube_codegen.sh"
|
||||
|
||||
echo "# Generating Traefik clientset and deepcopy code ..."
|
||||
kube::codegen::gen_helpers \
|
||||
--input-pkg-root "${PROJECT_MODULE}/pkg" \
|
||||
--output-base "$(dirname "${BASH_SOURCE[0]}")/../../../.." \
|
||||
--boilerplate "/go/src/${PROJECT_MODULE}/script/boilerplate.go.tmpl"
|
||||
--boilerplate "$(dirname "${BASH_SOURCE[0]}")/boilerplate.go.tmpl" \
|
||||
"${CURRENT_DIR}"
|
||||
|
||||
kube::codegen::gen_client \
|
||||
--with-watch \
|
||||
--input-pkg-root "${PROJECT_MODULE}/${MODULE_VERSION}/pkg/provider/kubernetes/crd" \
|
||||
--output-pkg-root "${PROJECT_MODULE}/${MODULE_VERSION}/pkg/provider/kubernetes/crd/generated" \
|
||||
--output-base "$(dirname "${BASH_SOURCE[0]}")/../../../.." \
|
||||
--boilerplate "/go/src/${PROJECT_MODULE}/script/boilerplate.go.tmpl"
|
||||
--output-dir "${CURRENT_DIR}/pkg/provider/kubernetes/crd/generated" \
|
||||
--output-pkg "${PROJECT_MODULE}/${MODULE_VERSION}/pkg/provider/kubernetes/crd/generated" \
|
||||
--boilerplate "$(dirname "${BASH_SOURCE[0]}")/boilerplate.go.tmpl" \
|
||||
"${CURRENT_DIR}/pkg/provider/kubernetes/crd"
|
||||
|
||||
rm -rf "/go/src/${PROJECT_MODULE}/${MODULE_VERSION}"
|
||||
echo "# Generating the CRD definitions for the documentation ..."
|
||||
controller-gen crd:crdVersions=v1 \
|
||||
paths={./pkg/provider/kubernetes/crd/traefikio/v1alpha1/...} \
|
||||
output:dir=./docs/content/reference/dynamic-configuration/
|
||||
|
||||
echo "# Concatenate the CRD definitions for publication and integration tests ..."
|
||||
cat "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/traefik.io_*.yaml > "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
|
||||
cp -f "${CURRENT_DIR}"/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml "${CURRENT_DIR}"/integration/fixtures/k8s/01-traefik-crd.yml
|
||||
|
@ -1,22 +0,0 @@
|
||||
FROM golang:1.23
|
||||
|
||||
ARG USER=$USER
|
||||
ARG UID=$UID
|
||||
ARG GID=$GID
|
||||
RUN useradd -l -m ${USER} --uid=${UID} && echo "${USER}:" chpasswd
|
||||
USER ${UID}:${GID}
|
||||
|
||||
ARG KUBE_VERSION
|
||||
|
||||
RUN go install k8s.io/code-generator/cmd/defaulter-gen@$KUBE_VERSION
|
||||
RUN go install k8s.io/code-generator/cmd/client-gen@$KUBE_VERSION
|
||||
RUN go install k8s.io/code-generator/cmd/lister-gen@$KUBE_VERSION
|
||||
RUN go install k8s.io/code-generator/cmd/informer-gen@$KUBE_VERSION
|
||||
RUN go install k8s.io/code-generator/cmd/deepcopy-gen@$KUBE_VERSION
|
||||
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.1
|
||||
|
||||
RUN mkdir -p $GOPATH/src/k8s.io/code-generator
|
||||
RUN cp -R $GOPATH/pkg/mod/k8s.io/code-generator@$KUBE_VERSION/* $GOPATH/src/k8s.io/code-generator/
|
||||
RUN chmod +x $GOPATH/src/k8s.io/code-generator/kube_codegen.sh
|
||||
|
||||
WORKDIR $GOPATH/src/k8s.io/code-generator
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||
OutputType = "file"
|
||||
FileName = "traefik_changelog.md"
|
||||
|
||||
# example new bugfix v3.3.3
|
||||
# example new bugfix v3.3.4
|
||||
CurrentRef = "v3.3"
|
||||
PreviousRef = "v3.3.2"
|
||||
PreviousRef = "v3.3.3"
|
||||
BaseBranch = "v3.3"
|
||||
FutureCurrentRefName = "v3.3.3"
|
||||
FutureCurrentRefName = "v3.3.4"
|
||||
|
||||
ThresholdPreviousRef = 10
|
||||
ThresholdCurrentRef = 10
|
||||
|
Loading…
x
Reference in New Issue
Block a user