1
0
Fork 0

Merge branch v3.4 into master

This commit is contained in:
kevinpollet 2025-06-02 16:54:12 +02:00
commit 289d6e5dca
No known key found for this signature in database
GPG key ID: 0C9A5DDD1B292453
195 changed files with 1963 additions and 892 deletions

View file

@ -15,8 +15,6 @@ A Use Case Using Docker
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
```yaml
version: '3'
services:
reverse-proxy:
# The official v3 Traefik docker image
@ -50,8 +48,6 @@ Now that you have a Traefik instance up and running, you will deploy new service
Edit your `docker-compose.yml` file and add the following at the end of your file.
```yaml
version: '3'
services:
...

View file

@ -13,7 +13,7 @@ You can configure Traefik to use an ACME provider (like Let's Encrypt) for autom
!!! warning "Let's Encrypt and Rate Limiting"
Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to **one week**, and cannot be overridden.
When running Traefik in a container this file should be persisted across restarts.
When running Traefik in a container the `acme.json` file should be persisted across restarts.
If Traefik requests new certificates each time it starts up, a crash-looping container can quickly reach Let's Encrypt's ratelimits.
To configure where certificates are stored, please take a look at the [storage](#storage) configuration.
@ -795,6 +795,8 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
_Optional, Default=2160_
`certificatesDuration` specifies the duration (in hours) of the certificates issued by the CA server. It is used to determine when to renew the certificate, but it **doesn't** define the duration of the certificates, that is up to the CA server.
`certificatesDuration` is used to calculate two durations:
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.

View file

@ -677,3 +677,32 @@ it can lead to unsafe routing when the `sanitizePath` option is set to `false`.
Setting the `sanitizePath` option to `false` is not safe.
Ensure every request is properly url encoded instead.
## v2.11.25
### Request Path Normalization
Since `v2.11.25`, the request path is now normalized by decoding unreserved characters in the request path,
and also uppercasing the percent-encoded characters.
This follows [RFC 3986 percent-encoding normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.2),
and [RFC 3986 case normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
The normalization happens before the request path is sanitized,
and cannot be disabled.
This notably helps with encoded dots characters (which are unreserved characters) to be sanitized properly.
### Routing Path
Since `v2.11.25`, the reserved characters [(as per RFC 3986)](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2) are kept encoded in the request path when matching the router rules.
Those characters, when decoded, change the meaning of the request path for routing purposes,
and Traefik now keeps them encoded to avoid any ambiguity.
### Request Path Matching Examples
| Request Path | Router Rule | Traefik v2.11.24 | Traefik v2.11.25 |
|-------------------|------------------------|------------------|------------------|
| `/foo%2Fbar` | PathPrefix(`/foo/bar`) | Match | No match |
| `/foo/../bar` | PathPrefix(`/foo`) | No match | No match |
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |

View file

@ -290,3 +290,32 @@ and to help with the migration from v2 to v3.
The `ruleSyntax` router's option was used to override the default rule syntax for a specific router.
In preparation for the next major release, please remove any use of these two options and use the v3 syntax for writing the router's rules.
## v3.4.1
### Request Path Normalization
Since `v3.4.1`, the request path is now normalized by decoding unreserved characters in the request path,
and also uppercasing the percent-encoded characters.
This follows [RFC 3986 percent-encoding normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.2),
and [RFC 3986 case normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
The normalization happens before the request path is sanitized,
and cannot be disabled.
This notably helps with encoded dots characters (which are unreserved characters) to be sanitized properly.
### Routing Path
Since `v3.4.1`, the reserved characters [(as per RFC 3986)](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2) are kept encoded in the request path when matching the router rules.
Those characters, when decoded, change the meaning of the request path for routing purposes,
and Traefik now keeps them encoded to avoid any ambiguity.
### Request Path Matching Examples
| Request Path | Router Rule | Traefik v3.4.0 | Traefik v3.4.1 |
|-------------------|------------------------|----------------|----------------|
| `/foo%2Fbar` | PathPrefix(`/foo/bar`) | Match | No match |
| `/foo/../bar` | PathPrefix(`/foo`) | No match | No match |
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |

View file

@ -288,8 +288,6 @@ It is possible to configure the Traefik to timestamp in a specific timezone by e
Example utilizing Docker Compose:
```yaml
version: "3.7"
services:
traefik:
image: traefik:v3.4

View file

@ -40,7 +40,6 @@ This provider works with [Docker (standalone) Engine](https://docs.docker.com/en
Attaching labels to containers (in your docker compose file)
```yaml
version: "3"
services:
my-container:
# ...
@ -162,8 +161,6 @@ See the [Docker API Access](#docker-api-access) section for more information.
The docker-compose file shares the docker sock with the Traefik container
```yaml
version: '3'
services:
traefik:
image: traefik:v3.4 # The official v3 Traefik docker image

View file

@ -53,7 +53,6 @@ This provider works with [Docker Swarm Mode](https://docs.docker.com/engine/swar
then that service is automatically assigned to the router.
```yaml
version: "3"
services:
my-container:
deploy:
@ -176,8 +175,6 @@ docker service create \
```
```yml tab="With Docker Compose"
version: '3'
services:
traefik:
# ...
@ -208,8 +205,6 @@ See the [Docker Swarm API Access](#docker-api-access) section for more informati
The docker-compose file shares the docker sock with the Traefik container
```yaml
version: '3'
services:
traefik:
image: traefik:v3.4 # The official v3 Traefik docker image

View file

@ -2291,7 +2291,7 @@ spec:
type: object
x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap)
rule: '!has(self.secret) || !has(self.configMap)'
type: array
rootCAsSecrets:
description: |-
@ -2436,7 +2436,7 @@ spec:
type: object
x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap)
rule: '!has(self.secret) || !has(self.configMap)'
type: array
rootCAsSecrets:
description: |-

View file

@ -134,7 +134,7 @@ spec:
type: object
x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap)
rule: '!has(self.secret) || !has(self.configMap)'
type: array
rootCAsSecrets:
description: |-

View file

@ -110,7 +110,7 @@ spec:
type: object
x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap)
rule: '!has(self.secret) || !has(self.configMap)'
type: array
rootCAsSecrets:
description: |-

View file

@ -199,8 +199,6 @@ It is possible to configure the Traefik to timestamp in a specific timezone by e
Example utilizing Docker Compose:
```yaml
version: "3.7"
services:
traefik:
image: traefik:v3.4

View file

@ -29,7 +29,6 @@ providers:
Attach labels to containers (in your Docker compose file)
```yaml
version: "3"
services:
my-container:
# ...
@ -67,8 +66,6 @@ See the [Docker API Access](#docker-api-access) section for more information.
The docker-compose file shares the docker sock with the Traefik container
```yaml
version: '3'
services:
traefik:
image: traefik:v3.1 # The official v3 Traefik docker image

View file

@ -33,7 +33,6 @@ When there is only one service, and the router does not specify a service,
then that service is automatically assigned to the router.
```yaml tab="Labels"
version: "3"
services:
my-container:
deploy:
@ -73,8 +72,6 @@ See the [Docker Swarm API Access](#docker-api-access) section for more informati
The docker-compose file shares the docker sock with the Traefik container
```yaml
version: '3'
services:
traefik:
image: traefik:v3.1 # The official v3 Traefik docker image
@ -405,8 +402,6 @@ docker service create \
```
```yml tab="With Docker Compose"
version: '3'
services:
traefik:
# ...

View file

@ -72,8 +72,6 @@ When using Docker or Amazon ECS, you can define routing configuration using cont
When deploying a Docker container, you can specify labels to define routing rules and services:
```yaml
version: '3'
services:
my-service:
image: my-image

View file

@ -202,109 +202,6 @@ spec:
- `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 |
@ -362,5 +259,5 @@ 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"
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="1747282426";NA="1778818426"SAN="*.example.org,*.example.net,*.example.com,test@example.org,test@example.net,10.0.1.0,10.0.1.2"
```

View file

@ -35,7 +35,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Attaching labels to containers (in your docker compose file)
```yaml
version: "3"
services:
my-container:
# ...
@ -48,7 +47,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml
version: "3"
services:
my-container:
# ...
@ -71,7 +69,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
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:
# ...

View file

@ -48,7 +48,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
then that service is automatically assigned to the router.
```yaml
version: "3"
services:
my-container:
deploy:
@ -67,7 +66,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml
version: "3"
services:
my-container:
# ...
@ -93,7 +91,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
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:
# ...

View file

@ -42,7 +42,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Attaching labels to containers (in your docker compose file)
```yaml
version: "3"
services:
my-container:
# ...
@ -55,7 +54,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml
version: "3"
services:
my-container:
# ...
@ -78,7 +76,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
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:
# ...

View file

@ -55,7 +55,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
then that service is automatically assigned to the router.
```yaml
version: "3"
services:
my-container:
deploy:
@ -74,7 +73,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml
version: "3"
services:
my-container:
# ...
@ -100,7 +98,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
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:
# ...

View file

@ -5,7 +5,7 @@ description: "Enforce strict ContentLength validation in Traefik by streaming
Traefik acts as a streaming proxy. By default, it checks each chunk of data against the `Content-Length` header as it passes it on to the backend or client. This live check blocks truncated or overlong streams without holding the entire message.
If you need Traefik to read and verify the full body before any data moves on, add the [buffering middleware](../../reference/routing-configuration/http/middlewares/buffering.md):
If you need Traefik to read and verify the full body before any data moves on, add the [buffering middleware](../middlewares/http/buffering.md):
```yaml
http:

View file

@ -1,5 +1,3 @@
version: "3.3"
services:
traefik:

View file

@ -1,5 +1,3 @@
version: "3.3"
secrets:
ovh_endpoint:
file: "./secrets/ovh_endpoint.secret"

View file

@ -1,5 +1,3 @@
version: "3.3"
services:
traefik:

View file

@ -1,5 +1,3 @@
version: "3.3"
services:
traefik:

View file

@ -1,5 +1,3 @@
version: "3.3"
services:
traefik:

View file

@ -23,8 +23,6 @@ Create a `docker-compose.yml` file with the following content:
You can use a [pre-existing network](https://docs.docker.com/compose/networking/#use-a-pre-existing-network "Link to Docker Compose networking docs") too.
```yaml
version: "3.3"
networks:
traefiknet: {}

View file

@ -0,0 +1,355 @@
---
title: "Traefik WebSocket Documentation"
description: "How to configure WebSocket and WebSocket Secure (WSS) connections with Traefik Proxy."
---
# WebSocket
Configuring Traefik to handle WebSocket and WebSocket Secure (WSS) connections.
{: .subtitle }
## Overview
WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection.
WebSocket Secure (WSS) is the encrypted version of WebSocket, using TLS/SSL encryption.
Traefik supports WebSocket and WebSocket Secure (WSS) out of the box. This guide will walk through examples of how to configure Traefik for different WebSocket scenarios.
## Basic WebSocket Configuration
A basic WebSocket configuration only requires defining a router and a service that points to your WebSocket server.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-websocket.rule=Host(`ws.example.com`)"
- "traefik.http.routers.my-websocket.service=my-websocket-service"
- "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-route
spec:
entryPoints:
- web
routes:
- match: Host(`ws.example.com`)
kind: Rule
services:
- name: my-websocket-service
port: 8000
```
```yaml tab="File (YAML)"
http:
routers:
my-websocket:
rule: "Host(`ws.example.com`)"
service: my-websocket-service
services:
my-websocket-service:
loadBalancer:
servers:
- url: "http://my-websocket-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-websocket]
rule = "Host(`ws.example.com`)"
service = "my-websocket-service"
[http.services]
[http.services.my-websocket-service]
[http.services.my-websocket-service.loadBalancer]
[[http.services.my-websocket-service.loadBalancer.servers]]
url = "http://my-websocket-server:8000"
```
## WebSocket Secure (WSS) Configuration
WebSocket Secure (WSS) requires TLS configuration.
The client connects using the `wss://` protocol instead of `ws://`.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-websocket-secure.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-websocket-secure.service=my-websocket-service"
- "traefik.http.routers.my-websocket-secure.tls=true"
- "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-secure-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-websocket-service
port: 8000
tls: {}
```
```yaml tab="File (YAML)"
http:
routers:
my-websocket-secure:
rule: "Host(`wss.example.com`)"
service: my-websocket-service
tls: {}
services:
my-websocket-service:
loadBalancer:
servers:
- url: "http://my-websocket-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-websocket-secure]
rule = "Host(`wss.example.com`)"
service = "my-websocket-service"
[http.routers.my-websocket-secure.tls]
[http.services]
[http.services.my-websocket-service]
[http.services.my-websocket-service.loadBalancer]
[[http.services.my-websocket-service.loadBalancer.servers]]
url = "http://my-websocket-server:8000"
```
## SSL Termination for WebSockets
In this scenario, clients connect to Traefik using WSS (encrypted), but Traefik connects to your backend server using WS (unencrypted).
This is called SSL termination.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-wss-termination.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-wss-termination.service=my-ws-service"
- "traefik.http.routers.my-wss-termination.tls=true"
- "traefik.http.services.my-ws-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-wss-termination-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-ws-service
port: 8000
tls: {}
```
```yaml tab="File (YAML)"
http:
routers:
my-wss-termination:
rule: "Host(`wss.example.com`)"
service: my-ws-service
tls: {}
services:
my-ws-service:
loadBalancer:
servers:
- url: "http://my-ws-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-wss-termination]
rule = "Host(`wss.example.com`)"
service = "my-ws-service"
[http.routers.my-wss-termination.tls]
[http.services]
[http.services.my-ws-service]
[http.services.my-ws-service.loadBalancer]
[[http.services.my-ws-service.loadBalancer.servers]]
url = "http://my-ws-server:8000"
```
## End-to-End WebSocket Secure (WSS)
For end-to-end encryption, Traefik can be configured to connect to your backend using HTTPS.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-wss-e2e.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-wss-e2e.service=my-wss-service"
- "traefik.http.routers.my-wss-e2e.tls=true"
- "traefik.http.services.my-wss-service.loadbalancer.server.port=8443"
# If the backend uses a self-signed certificate
- "traefik.http.serversTransports.insecureTransport.insecureSkipVerify=true"
- "traefik.http.services.my-wss-service.loadBalancer.serversTransport=insecureTransport"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: insecure-transport
spec:
insecureSkipVerify: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-wss-e2e-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-wss-service
port: 8443
serversTransport: insecure-transport
tls: {}
```
```yaml tab="File (YAML)"
http:
serversTransports:
insecureTransport:
insecureSkipVerify: true
routers:
my-wss-e2e:
rule: "Host(`wss.example.com`)"
service: my-wss-service
tls: {}
services:
my-wss-service:
loadBalancer:
serversTransport: insecureTransport
servers:
- url: "https://my-wss-server:8443"
```
```toml tab="File (TOML)"
[http.serversTransports]
[http.serversTransports.insecureTransport]
insecureSkipVerify = true
[http.routers]
[http.routers.my-wss-e2e]
rule = "Host(`wss.example.com`)"
service = "my-wss-service"
[http.routers.my-wss-e2e.tls]
[http.services]
[http.services.my-wss-service]
[http.services.my-wss-service.loadBalancer]
serversTransport = "insecureTransport"
[[http.services.my-wss-service.loadBalancer.servers]]
url = "https://my-wss-server:8443"
```
## EntryPoints Configuration for WebSockets
In your Traefik static configuration, you'll need to define entryPoints for both WS and WSS:
```yaml tab="File (YAML)"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
```
```toml tab="File (TOML)"
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
```
## Testing WebSocket Connections
You can test your WebSocket configuration using various tools:
1. Browser Developer Tools: Most modern browsers include WebSocket debugging in their developer tools.
2. WebSocket client tools like [wscat](https://github.com/websockets/wscat) or online tools like [Piesocket's WebSocket Tester](https://www.piesocket.com/websocket-tester).
Example wscat commands:
```bash
# Test standard WebSocket
wscat -c ws://ws.example.com
# Test WebSocket Secure
wscat -c wss://wss.example.com
```
## Common Issues and Solutions
### Headers and Origin Checks
Some WebSocket servers implement origin checking. Traefik passes the original headers to your backend, including the `Origin` header.
If you need to manipulate headers for WebSocket connections, you can use Traefik's Headers middleware:
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.middlewares.my-headers.headers.customrequestheaders.Origin=https://allowed-origin.com"
- "traefik.http.routers.my-websocket.middlewares=my-headers"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: my-headers
spec:
headers:
customRequestHeaders:
Origin: "https://allowed-origin.com"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-route
spec:
routes:
- match: Host(`ws.example.com`)
kind: Rule
middlewares:
- name: my-headers
services:
- name: my-websocket-service
port: 8000
```
### Certificate Issues with WSS
If you're experiencing certificate issues with WSS:
1. Ensure your certificates are valid and not expired
2. For testing with self-signed certificates, configure your clients to accept them
3. When using Let's Encrypt, ensure your domain is properly configured
For backends with self-signed certificates, use the `insecureSkipVerify` option in the ServersTransport configuration as shown in the examples above.

View file

@ -171,6 +171,7 @@ nav:
- 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
- 'Kubernetes and cert-manager': 'user-guides/cert-manager.md'
- 'gRPC Examples': 'user-guides/grpc.md'
- 'WebSocket Examples': 'user-guides/websocket.md'
- 'Docker':
- 'Basic Example': 'user-guides/docker-compose/basic-example/index.md'
- 'HTTPS with Let''s Encrypt':