Merge branch 'v2.0' into master

This commit is contained in:
Fernandez Ludovic 2019-10-29 09:52:45 +01:00
commit d66dd01438
46 changed files with 911 additions and 484 deletions

View file

@ -1,3 +1,42 @@
## [v2.0.4](https://github.com/containous/traefik/tree/v2.0.4) (2019-10-28)
[All Commits](https://github.com/containous/traefik/compare/v2.0.3...v2.0.4)
Fixes releases system.
Same changelog as v2.0.3.
## [v2.0.3](https://github.com/containous/traefik/tree/v2.0.3) (2019-10-28)
[All Commits](https://github.com/containous/traefik/compare/v2.0.2...v2.0.3)
**Bug fixes:**
- **[acme,logs]** Use debug for log about skipping addition of cert ([#5641](https://github.com/containous/traefik/pull/5641) by [sylr](https://github.com/sylr))
- **[file]** fix: add filename in the file provider logs. ([#5636](https://github.com/containous/traefik/pull/5636) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd,k8s/ingress]** Remove unnecessary reload of the configuration. ([#5707](https://github.com/containous/traefik/pull/5707) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd,k8s/ingress]** Fixing support for HTTPs backends with Kubernetes ExternalName services ([#5660](https://github.com/containous/traefik/pull/5660) by [kpeiruza](https://github.com/kpeiruza))
- **[k8s,k8s/ingress]** Normalize service and router names for ingress. ([#5623](https://github.com/containous/traefik/pull/5623) by [ldez](https://github.com/ldez))
- **[logs]** Set proxy protocol logger to DEBUG level ([#5712](https://github.com/containous/traefik/pull/5712) by [mmatur](https://github.com/mmatur))
- **[middleware]** fix: add stacktrace when recover. ([#5654](https://github.com/containous/traefik/pull/5654) by [ldez](https://github.com/ldez))
- **[tracing]** Let instana/go-sensor handle default agent host ([#5658](https://github.com/containous/traefik/pull/5658) by [sylr](https://github.com/sylr))
- **[tracing]** fix: default tracing backend. ([#5717](https://github.com/containous/traefik/pull/5717) by [ldez](https://github.com/ldez))
- fix: deep copy of passHostHeader on ServersLoadBalancer. ([#5720](https://github.com/containous/traefik/pull/5720) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme]** Fix acme storage file docker mounting example ([#5633](https://github.com/containous/traefik/pull/5633) by [jansauer](https://github.com/jansauer))
- **[acme]** fix incorrect DNS reference ([#5666](https://github.com/containous/traefik/pull/5666) by [oskapt](https://github.com/oskapt))
- **[logs]** Clarify unit of duration field in access log ([#5664](https://github.com/containous/traefik/pull/5664) by [Sarke](https://github.com/Sarke))
- **[middleware]** Fix Security Headers Doc ([#5706](https://github.com/containous/traefik/pull/5706) by [FlorianPerrot](https://github.com/FlorianPerrot))
- **[middleware]** Migration guide: pathprefixstrip migration ([#5600](https://github.com/containous/traefik/pull/5600) by [dduportal](https://github.com/dduportal))
- **[middleware]** fix ForwardAuth tls.skipverify examples ([#5683](https://github.com/containous/traefik/pull/5683) by [remche](https://github.com/remche))
- **[rules]** Add documentation about backtick for rule definition. ([#5714](https://github.com/containous/traefik/pull/5714) by [ldez](https://github.com/ldez))
- **[webui]** Improve documentation of the router rules for API and dashboard ([#5625](https://github.com/containous/traefik/pull/5625) by [dduportal](https://github.com/dduportal))
- doc: @ is not authorized in names definition. ([#5734](https://github.com/containous/traefik/pull/5734) by [ldez](https://github.com/ldez))
- Remove obsolete v2 remark from README ([#5669](https://github.com/containous/traefik/pull/5669) by [dragetd](https://github.com/dragetd))
- Fix spelling mistake: "founded" -> "found" ([#5674](https://github.com/containous/traefik/pull/5674) by [ocanty](https://github.com/ocanty))
- fix typo for stripPrefix in tab File (YAML) ([#5694](https://github.com/containous/traefik/pull/5694) by [nalakawula](https://github.com/nalakawula))
- Add example for changing the port used by traefik to connect to a service ([#5224](https://github.com/containous/traefik/pull/5224) by [robertbaker](https://github.com/robertbaker))
**Misc:**
- **[logs,middleware]** Cherry pick v1.7 into v2.0 ([#5735](https://github.com/containous/traefik/pull/5735) by [jbdoumenjou](https://github.com/jbdoumenjou))
## [v2.0.2](https://github.com/containous/traefik/tree/v2.0.2) (2019-10-09)
[All Commits](https://github.com/containous/traefik/compare/v2.0.1...v2.0.2)
@ -70,6 +109,24 @@
- Add the router priority documentation ([#5481](https://github.com/containous/traefik/pull/5481) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Improve the Migration Guide ([#5391](https://github.com/containous/traefik/pull/5391) by [jbdoumenjou](https://github.com/jbdoumenjou))
## [v1.7.18](https://github.com/containous/traefik/tree/v1.7.18) (2019-09-23)
[All Commits](https://github.com/containous/traefik/compare/v1.7.17...v1.7.18)
**Bug fixes:**
- **[go,security]** This version is compiled with [Go 1.12.10](https://groups.google.com/d/msg/golang-announce/cszieYyuL9Q/g4Z7pKaqAgAJ), which fixes a vulnerability in previous versions. See the [CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16276) about it for more details.
## [v1.7.17](https://github.com/containous/traefik/tree/v1.7.17) (2019-09-23)
[All Commits](https://github.com/containous/traefik/compare/v1.7.16...v1.7.17)
**Bug fixes:**
- **[logs,middleware]** Avoid closing stdout when the accesslog handler is closed ([#5459](https://github.com/containous/traefik/pull/5459) by [nrwiersma](https://github.com/nrwiersma))
- **[middleware]** Actually send header and code during WriteHeader, if needed ([#5404](https://github.com/containous/traefik/pull/5404) by [mpl](https://github.com/mpl))
**Documentation:**
- **[k8s]** Add note clarifying client certificate header ([#5362](https://github.com/containous/traefik/pull/5362) by [bradjones1](https://github.com/bradjones1))
- **[webui]** Update docs links. ([#5412](https://github.com/containous/traefik/pull/5412) by [ldez](https://github.com/ldez))
- Update Traefik image version. ([#5399](https://github.com/containous/traefik/pull/5399) by [ldez](https://github.com/ldez))
## [v2.0.0](https://github.com/containous/traefik/tree/v2.0.0) (2019-09-16)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-alpha1...v2.0.0)
@ -414,6 +471,29 @@
- fix a service with one server .yaml example ([#5373](https://github.com/containous/traefik/pull/5373) by [zaverden](https://github.com/zaverden))
- fix: services configuration documentation. ([#5359](https://github.com/containous/traefik/pull/5359) by [ldez](https://github.com/ldez))
## [v1.7.16](https://github.com/containous/traefik/tree/v1.7.16) (2019-09-13)
[All Commits](https://github.com/containous/traefik/compare/v1.7.15...v1.7.16)
**Bug fixes:**
- **[middleware,websocket]** implement Flusher and Hijacker for codeCatcher ([#5376](https://github.com/containous/traefik/pull/5376) by [mpl](https://github.com/mpl))
## [v1.7.15](https://github.com/containous/traefik/tree/v1.7.15) (2019-09-12)
[All Commits](https://github.com/containous/traefik/compare/v1.7.14...v1.7.15)
**Bug fixes:**
- **[authentication,k8s/ingress]** Kubernetes support for Auth.HeaderField ([#5235](https://github.com/containous/traefik/pull/5235) by [ErikWegner](https://github.com/ErikWegner))
- **[k8s,k8s/ingress]** Finish kubernetes throttling refactoring ([#5269](https://github.com/containous/traefik/pull/5269) by [mpl](https://github.com/mpl))
- **[k8s]** Throttle Kubernetes config refresh ([#4716](https://github.com/containous/traefik/pull/4716) by [benweissmann](https://github.com/benweissmann))
- **[k8s]** Fix wrong handling of insecure tls auth forward ingress annotation ([#5319](https://github.com/containous/traefik/pull/5319) by [majkrzak](https://github.com/majkrzak))
- **[middleware]** error pages: do not buffer response when it's not an error ([#5285](https://github.com/containous/traefik/pull/5285) by [mpl](https://github.com/mpl))
- **[tls]** Consider default cert domain in certificate store ([#5353](https://github.com/containous/traefik/pull/5353) by [nrwiersma](https://github.com/nrwiersma))
- **[tls]** Add TLS minversion constraint ([#5356](https://github.com/containous/traefik/pull/5356) by [dtomcej](https://github.com/dtomcej))
**Documentation:**
- **[acme]** Update Acme doc - Vultr Wildcard & Root ([#5320](https://github.com/containous/traefik/pull/5320) by [ddymko](https://github.com/ddymko))
- **[consulcatalog]** Typo in basic auth usersFile label consul-catalog ([#5230](https://github.com/containous/traefik/pull/5230) by [pitan](https://github.com/pitan))
- **[logs]** Improve Access Logs Documentation page ([#5238](https://github.com/containous/traefik/pull/5238) by [dduportal](https://github.com/dduportal))
## [v2.0.0-rc3](https://github.com/containous/traefik/tree/v2.0.0-rc3) (2019-09-10)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc2...v2.0.0-rc3)

View file

@ -131,7 +131,7 @@ generate-crd:
## Create packages for the release
release-packages: generate-webui build-dev-image
rm -rf dist
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish --timeout="60m"
$(DOCKER_RUN_TRAEFIK_NOTTY) tar cfz dist/traefik-${VERSION}.src.tar.gz \
--exclude-vcs \
--exclude .idea \

View file

@ -33,7 +33,7 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
---
:warning: Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
:warning: Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
## Overview
@ -87,10 +87,11 @@ You can access the simple HTML frontend of Traefik.
## Documentation
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
You can find the complete documentation of Traefik v2 at [https://docs.traefik.io](https://docs.traefik.io).
:warning: If you're testing out v2, please ensure you are using the [v2 documentation](https://docs.traefik.io/).
If you are using Traefik v1, you can find the complete documentation at [https://docs.traefik.io/v1.7/](https://docs.traefik.io/v1.7/)
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
## Support

View file

@ -16,8 +16,8 @@ The _dynamic configuration_ contains everything that defines how the requests ar
This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.
!!! warning "Incompatible Configuration"
Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now.
If you're testing out v2, please ensure you are using a v2 configuration.
Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now.
If you are running v2, please ensure you are using a v2 configuration.
## The Dynamic Configuration

View file

@ -382,7 +382,7 @@ ACME certificates can be stored in a JSON file that needs to have a `600` file m
In Docker you can mount either the JSON file, or the folder containing it:
```bash
docker run -v "/my/host/acme.json:acme.json" traefik
docker run -v "/my/host/acme.json:/acme.json" traefik
```
```bash

View file

@ -509,7 +509,8 @@ metadata:
spec:
forwardAuth:
address: https://authserver.com/auth
insecureSkipVerify: true
tls:
insecureSkipVerify: true
```
```yaml tab="Consul Catalog"
@ -531,7 +532,8 @@ labels:
[http.middlewares]
[http.middlewares.test-auth.forwardAuth]
address = "https://authserver.com/auth"
insecureSkipVerify: true
[http.middlewares.test-auth.forwardAuth.tls]
insecureSkipVerify: true
```
```yaml tab="File (YAML)"
@ -540,5 +542,6 @@ http:
test-auth:
forwardAuth:
address: "https://authserver.com/auth"
insecureSkipVerify: true
tls:
insecureSkipVerify: true
```

View file

@ -176,8 +176,8 @@ labels:
```toml tab="File (TOML)"
[http.middlewares]
[http.middlewares.testHeader.headers]
FrameDeny = true
SSLRedirect = true
frameDeny = true
sslRedirect = true
```
```yaml tab="File (YAML)"
@ -185,8 +185,8 @@ http:
middlewares:
testHeader:
headers:
FrameDeny: true
SSLRedirect: true
frameDeny: true
sslRedirect: true
```
### CORS Headers

View file

@ -245,7 +245,10 @@ PassTLSClientCert can add two headers to the request:
- `X-Forwarded-Tls-Client-Cert-Info` that contains all the selected certificate information in an escaped string.
!!! info
The headers are filled with escaped string so it can be safely placed inside a URL query.
* The headers are filled with escaped string so it can be safely placed inside a URL query.
* These options only work accordingly to the [MutualTLS configuration](../https/tls.md#client-authentication-mtls).
That is to say, only the certificates that match the `clientAuth.clientAuthType` policy are passed.
In the following example, you can see a complete certificate. We will use each part of it to explain the middleware options.

View file

@ -3,13 +3,13 @@
How to Migrate from Traefik v1 to Traefik v2.
{: .subtitle }
The version 2 of Traefik introduces a number of breaking changes,
The version 2 of Traefik introduces a number of breaking changes,
which require one to update their configuration when they migrate from v1 to v2.
The goal of this page is to recapitulate all of these changes, and in particular to give examples,
The goal of this page is to recapitulate all of these changes, and in particular to give examples,
feature by feature, of how the configuration looked like in v1, and how it now looks like in v2.
!!! info "Migration Helper"
We created a tool to help during the migration: [traefik-migration-tool](https://github.com/containous/traefik-migration-tool)
This tool allows to:
@ -32,7 +32,7 @@ Then any router can refer to an instance of the wanted middleware.
!!! example "One frontend with basic auth and one backend, become one router, one service, and one basic auth middleware."
!!! info "v1"
```yaml tab="Docker"
labels:
- "traefik.frontend.rule=Host:test.localhost;PathPrefix:/test"
@ -92,9 +92,9 @@ Then any router can refer to an instance of the wanted middleware.
[backends.backend1.loadBalancer]
method = "wrr"
```
!!! info "v2"
```yaml tab="Docker"
labels:
- "traefik.http.routers.router0.rule=Host(`bar.com`) && PathPrefix(`/test`)"
@ -103,7 +103,7 @@ Then any router can refer to an instance of the wanted middleware.
```
```yaml tab="K8s IngressRoute"
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
# https://docs.traefik.io/v2.0/providers/kubernetes-crd/#traefik-ingressroute-definition
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
@ -155,7 +155,7 @@ Then any router can refer to an instance of the wanted middleware.
[http.middlewares]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
@ -184,7 +184,7 @@ Then any router can refer to an instance of the wanted middleware.
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
## TLS configuration is now dynamic, per router.
## TLS Configuration Is Now Dynamic, per Router.
TLS parameters used to be specified in the static configuration, as an entryPoint field.
With Traefik v2, a new dynamic TLS section at the root contains all the desired TLS configurations.
@ -214,13 +214,13 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
certFile = "path/to/my.cert"
keyFile = "path/to/my.key"
```
```bash tab="CLI"
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key TLS.MinVersion:VersionTLS12 TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
```
!!! info "v2"
```toml tab="File (TOML)"
# dynamic configuration
[http.routers]
@ -250,7 +250,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
]
```
```yaml tab="File (YAML)"
http:
routers:
@ -275,9 +275,9 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
```
```yaml tab="K8s IngressRoute"
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
# https://docs.traefik.io/v2.0/providers/kubernetes-crd/#traefik-ingressroute-definition
apiVersion: traefik.containo.us/v1alpha1
kind: TLSOption
@ -310,11 +310,11 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
- name: whoami
port: 80
tls:
options:
options:
name: mytlsoption
namespace: default
```
```yaml tab="Docker"
labels:
# myTLSOptions must be defined by another provider, in this instance in the File Provider.
@ -322,7 +322,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
- "traefik.http.routers.router0.tls.options=myTLSOptions@file"
```
## HTTP to HTTPS Redirection is now configured on Routers
## HTTP to HTTPS Redirection Is Now Configured on Routers
Previously on Traefik v1, the redirection was applied on an entry point or on a frontend.
With Traefik v2 it is applied on a [Router](../routing/routers/index.md).
@ -350,14 +350,14 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
certFile = "examples/traefik.crt"
keyFile = "examples/traefik.key"
```
```bash tab="CLI"
--entrypoints=Name:web Address::80 Redirect.EntryPoint:web-secure
--entryPoints='Name:web-secure Address::443 TLS:path/to/my.cert,path/to/my.key'
```
!!! info "v2"
```yaml tab="Docker"
labels:
- traefik.http.routers.web.rule=Host(`foo.com`)
@ -454,9 +454,9 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
[[tls.certificates]]
certFile = "/path/to/domain.cert"
keyFile = "/path/to/domain.key"
keyFile = "/path/to/domain.key"
```
```yaml tab="File (YAML)"
## static configuration
# traefik.yml
@ -506,7 +506,139 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
certificates:
- certFile: /app/certs/server/server.pem
keyFile: /app/certs/server/server.pem
```
```
## Strip and Rewrite Path Prefixes
With the new core notions of v2 (introduced earlier in the section
["Frontends and Backends Are Dead... Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)),
transforming the URL path prefix of incoming requests is configured with [middlewares](../../middlewares/overview/),
after the routing step with [router rule `PathPrefix`](https://docs.traefik.io/v2.0/routing/routers/#rule).
Use Case: Incoming requests to `http://company.org/admin` are forwarded to the webapplication "admin",
with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, you must:
* First, configure a router named `admin` with a rule matching at least the path prefix with the `PathPrefix` keyword,
* Then, define a middlware of type [`stripprefix`](../../middlewares/stripprefix/), which remove the prefix `/admin`, associated to the router `admin`.
!!! example "Strip Path Prefix When Forwarding to Backend"
!!! info "v1"
```yaml tab="Docker"
labels:
- "traefik.frontend.rule=Host:company.org;PathPrefixStrip:/admin"
```
```yaml tab="Kubernetes Ingress"
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: traefik
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
spec:
rules:
- host: company.org
http:
paths:
- path: /admin
backend:
serviceName: admin-svc
servicePort: admin
```
```toml tab="File (TOML)"
[frontends.admin]
[frontends.admin.routes.admin_1]
rule = "Host:company.org;PathPrefixStrip:/admin"
```
!!! info "v2"
```yaml tab="Docker"
labels:
- "traefik.http.routers.admin.rule=Host(`company.org`) && PathPrefix(`/admin`)"
- "traefik.http.middlewares.admin-stripprefix.stripprefix.prefixes=/admin"
- "traefik.http.routers.web.middlewares=admin-stripprefix@docker"
```
```yaml tab="Kubernetes IngressRoute"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: http-redirect-ingressRoute
namespace: admin-web
spec:
entryPoints:
- web
routes:
- match: Host(`company.org`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: admin-svc
port: admin
middlewares:
- name: admin-stripprefix
---
kind: Middleware
metadata:
name: admin-stripprefix
spec:
stripPrefix:
prefixes:
- /admin
```
```toml tab="File (TOML)"
## Dynamic configuration
# dynamic-conf.toml
[http.routers.router1]
rule = "Host(`company.org`) && PathPrefix(`/admin`)"
service = "admin-svc"
entrypoints = ["web"]
middlewares = ["admin-stripprefix"]
[http.middlewares]
[http.middlewares.admin-stripprefix.stripPrefix]
prefixes = ["/admin"]
# ...
```
```yaml tab="File (YAML)"
## Dynamic Configuration
# dynamic-conf.yml
# As YAML Configuration File
http:
routers:
admin:
service: admin-svc
middlewares:
- "admin-stripprefix"
rule: "Host(`company.org`) && PathPrefix(`/admin`)"
middlewares:
admin-stripprefix:
stripPrefix:
prefixes:
- "/admin"
# ...
```
??? question "What About Other Path Transformations?"
Instead of removing the path prefix with the [`stripprefix` middleware](../../middlewares/stripprefix/), you can also:
* Add a path prefix with the [`addprefix` middleware](../../middlewares/addprefix/)
* Replace the complete path of the request with the [`replacepath` middleware](../../middlewares/replacepath/)
* ReplaceRewrite path using Regexp with the [`replacepathregex` middleware](../../middlewares/replacepathregex/)
* And a lot more on the [`middlewares` page](../../middlewares/overview/)
## ACME (LetsEncrypt)
@ -536,7 +668,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
[acme.httpChallenge]
entryPoint = "web"
```
```bash tab="CLI"
--defaultentrypoints=web-secure,web
--entryPoints=Name:web Address::80 Redirect.EntryPoint:web-secure
@ -547,9 +679,9 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
--acme.onHostRule=true
--acme.httpchallenge.entrypoint=http
```
!!! info "v2"
```toml tab="File (TOML)"
# static configuration
[entryPoints]
@ -566,7 +698,7 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
# used during the challenge
entryPoint = "web"
```
```yaml tab="File (YAML)"
entryPoints:
web:
@ -583,8 +715,8 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
httpChallenge:
# used during the challenge
entryPoint: web
```
```
```bash tab="CLI"
--entryPoints.web.address=":80"
--entryPoints.websecure.address=":443"
@ -601,7 +733,7 @@ There is no more log configuration at the root level.
!!! example "Simple log configuration"
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
logLevel = "DEBUG"
@ -610,15 +742,15 @@ There is no more log configuration at the root level.
filePath = "/path/to/traefik.log"
format = "json"
```
```bash tab="CLI"
--logLevel="DEBUG"
--traefikLog.filePath="/path/to/traefik.log"
--traefikLog.format="json"
```
!!! info "v2"
```toml tab="File (TOML)"
# static configuration
[log]
@ -626,15 +758,15 @@ There is no more log configuration at the root level.
filePath = "/path/to/log-file.log"
format = "json"
```
```yaml tab="File (YAML)"
# static configuration
log:
level: DEBUG
filePath: /path/to/log-file.log
format: json
```
```
```bash tab="CLI"
--log.level="DEBUG"
--log.filePath="/path/to/traefik.log"
@ -644,11 +776,11 @@ There is no more log configuration at the root level.
## Tracing
Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is gone, you just have to set your [tracing configuration](../observability/tracing/overview.md).
!!! example "Simple Jaeger tracing configuration"
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
[tracing]
@ -660,18 +792,18 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
samplingType = "const"
localAgentHostPort = "12.0.0.1:6831"
```
```bash tab="CLI"
--tracing.backend="jaeger"
--tracing.servicename="tracing"
--tracing.jaeger.localagenthostport="12.0.0.1:6831"
--tracing.jaeger.samplingparam="1.0"
--tracing.jaeger.samplingserverurl="http://12.0.0.1:5778/sampling"
--tracing.jaeger.samplingtype="const"
--tracing.jaeger.samplingtype="const"
```
!!! info "v2"
```toml tab="File (TOML)"
# static configuration
[tracing]
@ -682,7 +814,7 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
samplingType = "const"
localAgentHostPort = "12.0.0.1:6831"
```
```yaml tab="File (YAML)"
# static configuration
tracing:
@ -692,8 +824,8 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
samplingServerURL: 'http://12.0.0.1:5778/sampling'
samplingType: const
localAgentHostPort: '12.0.0.1:6831'
```
```
```bash tab="CLI"
--tracing.servicename="tracing"
--tracing.jaeger.localagenthostport="12.0.0.1:6831"
@ -705,33 +837,33 @@ Traefik v2 retains OpenTracing support. The `backend` root option from the v1 is
## Metrics
The v2 retains metrics tools and allows metrics to be configured for the entrypoints and/or services.
For a basic configuration, the [metrics configuration](../observability/metrics/overview.md) remains the same.
For a basic configuration, the [metrics configuration](../observability/metrics/overview.md) remains the same.
!!! example "Simple Prometheus metrics configuration"
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
[metrics.prometheus]
buckets = [0.1,0.3,1.2,5.0]
entryPoint = "traefik"
```
```bash tab="CLI"
--metrics.prometheus.buckets=[0.1,0.3,1.2,5.0]
--metrics.prometheus.entrypoint="traefik"
```
!!! info "v2"
```toml tab="File (TOML)"
# static configuration
[metrics.prometheus]
buckets = [0.1,0.3,1.2,5.0]
entryPoint = "metrics"
```
```yaml tab="File (YAML)"
# static configuration
metrics:
@ -742,22 +874,22 @@ For a basic configuration, the [metrics configuration](../observability/metrics/
- 1.2
- 5
entryPoint: metrics
```
```
```bash tab="CLI"
--metrics.prometheus.buckets=[0.1,0.3,1.2,5.0]
--metrics.prometheus.entrypoint="metrics"
```
## No more root level key/values
## No More Root Level Key/Values
To avoid any source of confusion, there are no more configuration at the root level.
Each root item has been moved to a related section or removed.
!!! example "From root to dedicated section"
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
checkNewVersion = false
@ -772,7 +904,7 @@ Each root item has been moved to a related section or removed.
defaultEntryPoints = ["web", "web-secure"]
keepTrailingSlash = false
```
```bash tab="CLI"
--checknewversion=false
--sendanonymoususage=true
@ -786,9 +918,9 @@ Each root item has been moved to a related section or removed.
--defaultentrypoints="web","web-secure"
--keeptrailingslash=true
```
!!! info "v2"
```toml tab="File (TOML)"
# static configuration
[global]
@ -804,9 +936,9 @@ Each root item has been moved to a related section or removed.
maxIdleConnsPerHost = 42
[providers]
providersThrottleDuration = 42
providersThrottleDuration = 42
```
```yaml tab="File (YAML)"
# static configuration
global:
@ -824,8 +956,8 @@ Each root item has been moved to a related section or removed.
providers:
providersThrottleDuration: 42
```
```
```bash tab="CLI"
--global.checknewversion=true
--global.sendanonymoususage=true
@ -835,7 +967,7 @@ Each root item has been moved to a related section or removed.
--serverstransport.maxidleconnsperhost=42
--providers.providersthrottleduration=42
```
## Dashboard
You need to activate the API to access the [dashboard](../operations/dashboard.md).
@ -847,11 +979,11 @@ As the dashboard access is now secured by default you can either:
!!! info "Dashboard with k8s and dedicated router"
As `api@internal` is not a Kubernetes service, you have to use the file provider or the `insecure` API option.
!!! example "Activate and access the dashboard"
!!! info "v1"
```toml tab="File (TOML)"
## static configuration
# traefik.toml
@ -868,14 +1000,14 @@ As the dashboard access is now secured by default you can either:
[api]
entryPoint = "web-secure"
```
```bash tab="CLI"
--entryPoints='Name:web-secure Address::443 TLS Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
--api
```
!!! info "v2"
```yaml tab="Docker"
# dynamic configuration
labels:
@ -916,7 +1048,7 @@ As the dashboard access is now secured by default you can either:
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
]
```
```yaml tab="File (YAML)"
## static configuration
# traefik.yaml
@ -952,8 +1084,8 @@ As the dashboard access is now secured by default you can either:
basicAuth:
users:
- 'test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'
```
```
## Providers
Supported [providers](../providers/overview.md), for now:
@ -976,7 +1108,7 @@ Supported [providers](../providers/overview.md), for now:
* [x] Rest
* [ ] Zookeeper
## Some Tips You Should Known
## Some Tips You Should Know
* Different sources of static configuration (file, CLI flags, ...) cannot be [mixed](../getting-started/configuration-overview.md#the-static-configuration).
* Now, configuration elements can be referenced between different providers by using the provider namespace notation: `@<provider>`.

View file

@ -180,7 +180,7 @@ accessLog:
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `StartUTC` | The time at which request processing started. |
| `StartLocal` | The local time at which request processing started. |
| `Duration` | The total time taken by processing the response, including the origin server's time but not the log writing time. |
| `Duration` | The total time taken (in nanoseconds) by processing the response, including the origin server's time but not the log writing time. |
| `FrontendName` | The name of the Traefik frontend. |
| `BackendName` | The name of the Traefik backend. |
| `BackendURL` | The URL of the Traefik backend. |

View file

@ -0,0 +1,4 @@
{
"extends": "../../.markdownlint.json",
"MD046": false
}

View file

@ -14,7 +14,7 @@ In production, it should be at least secured by authentication and authorization
A good sane default (non exhaustive) set of recommendations
would be to apply the following protection mechanisms:
* At the transport level:
* At the transport level:
NOT publicly exposing the API's port,
keeping it restricted to internal networks
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
@ -23,13 +23,16 @@ would be to apply the following protection mechanisms:
If you enable the API, a new special `service` named `api@internal` is created and can then be referenced in a router.
To enable the API handler:
To enable the API handler, use the following option on the
[static configuration](../getting-started/configuration-overview.md#the-static-configuration):
```toml tab="File (TOML)"
# Static Configuration
[api]
```
```yaml tab="File (YAML)"
# Static Configuration
api: {}
```
@ -37,11 +40,13 @@ api: {}
--api=true
```
And then you will be able to reference it like this:
And then define a routing configuration on Traefik itself with the
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration):
```yaml tab="Docker"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
@ -57,40 +62,42 @@ labels:
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
"traefik.http.routers.api.service": "api@internal"
"traefik.http.routers.api.middlewares": "auth"
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
"traefik.http.routers.api.service": "api@internal",
"traefik.http.routers.api.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="Rancher"
# Declaring the user list
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```toml tab="File (TOML)"
# Dynamic Configuration
[http.routers.my-api]
rule="PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
rule="Host(`traefik.domain.com`)
service="api@internal"
middlewares=["auth"]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:
routers:
api:
rule: PathPrefix(`/api`) || PathPrefix(`/dashboard`)
rule: Host(`traefik.domain.com`)
service: api@internal
middlewares:
- auth
@ -98,10 +105,32 @@ http:
auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
??? warning "The router's [rule](../../routing/routers#rule) must catch requests for the URI path `/api`"
Using an "Host" rule is recommended, by catching all the incoming traffic on this host domain to the API.
However, you can also use "path prefix" rule or any combination or rules.
```bash tab="Host Rule"
# Matches http://traefik.domain.com, http://traefik.domain.com/api
# or http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`)"
```
```bash tab="Path Prefix Rule"
# Matches http://api.traefik.domain.com/api or http://domain.com/api
# but does not match http://api.traefik.domain.com/hello
rule = "PathPrefix(`/api`)"
```
```bash tab="Combination of Rules"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
```
### `insecure`
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`.
@ -143,6 +172,9 @@ api:
--api.dashboard=true
```
!!! warning "With Dashboard enabled, the router [rule](../../routing/routers#rule) must catch requests for both `/api` and `/dashboard`"
Please check the [Dashboard documentation](./dashboard.md#dashboard-router-rule) to learn more about this and to get examples.
### `debug`
_Optional, Default=false_

View file

@ -28,7 +28,8 @@ There are 2 ways to configure and access the dashboard:
This is the **recommended** method.
Start by enabling the dashboard by using the following option from [Traefik's API](./api.md):
Start by enabling the dashboard by using the following option from [Traefik's API](./api.md)
on the [static configuration](../getting-started/configuration-overview.md#the-static-configuration):
```toml tab="File (TOML)"
[api]
@ -59,17 +60,103 @@ api:
--api.dashboard=true
```
Then specify a router associated to the service `api@internal` to allow:
Then define a routing configuration on Traefik itself,
with a router attached to the service `api@internal` in the
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration),
to allow defining:
- Defining one or more security features through [middlewares](../middlewares/overview.md)
- One or more security features through [middlewares](../middlewares/overview.md)
like authentication ([basicAuth](../middlewares/basicauth.md) , [digestAuth](../middlewares/digestauth.md),
[forwardAuth](../middlewares/forwardauth.md)) or [whitelisting](../middlewares/ipwhitelist.md).
- Defining your own [HTTP routing rule](../../routing/routers/#rule) for accessing the dashboard,
- A [router rule](#dashboard-router-rule) for accessing the dashboard,
through Traefik itself (sometimes referred as "Traefik-ception").
Please visit the ["Configuration" section of the API documentation](./api.md#configuration)
to learn about configuring a router with the service `api@internal` and enabling the security features.
??? example "Dashboard Dynamic Configuration Examples"
```yaml tab="Docker"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
"traefik.http.routers.api.service": "api@internal",
"traefik.http.routers.api.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="Rancher"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```toml tab="File (TOML)"
# Dynamic Configuration
[http.routers.my-api]
rule="Host(`traefik.domain.com`)
service="api@internal"
middlewares=["auth"]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:
routers:
api:
rule: Host(`traefik.domain.com`)
service: api@internal
middlewares:
- auth
middlewares:
auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
### Dashboard Router Rule
As underlined in the [documentation for the `api.dashboard` option](./api.md#dashboard),
the [router rule](../routing/routers/index.md#rule) defined for Traefik must match
the path prefixes `/api` and `/dashboard`.
We recommend to use a "Host Based rule" as ```Host(`traefik.domain.com`)``` to match everything on the host domain,
or to make sure that the defined rule captures both prefixes:
```bash tab="Host Rule"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
rule = "Host(`traefik.domain.com`)"
```
```bash tab="Path Prefix Rule"
# Matches http://traefik.domain.com/api , http://domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
```
```bash tab="Combination of Rules"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
```
## Insecure Mode

View file

@ -128,7 +128,7 @@ Traefik requires access to the docker socket to get its dynamic configuration.
??? info "Resources about Docker's Security"
- [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY)
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html)
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/)
- [A thread on Stack Overflow about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623)
- [To DinD or not to DinD](https://blog.loof.fr/2018/01/to-dind-or-not-do-dind.html)

View file

@ -580,7 +580,7 @@ Specifies the header name that will be used to store the trace ID.
Settings for Instana. (Default: ```false```)
`--tracing.instana.localagenthost`:
Set instana-agent's host that the reporter will used. (Default: ```localhost```)
Set instana-agent's host that the reporter will used.
`--tracing.instana.localagentport`:
Set instana-agent's port that the reporter will used. (Default: ```42699```)

View file

@ -580,7 +580,7 @@ Specifies the header name that will be used to store the trace ID.
Settings for Instana. (Default: ```false```)
`TRAEFIK_TRACING_INSTANA_LOCALAGENTHOST`:
Set instana-agent's host that the reporter will used. (Default: ```localhost```)
Set instana-agent's host that the reporter will used.
`TRAEFIK_TRACING_INSTANA_LOCALAGENTPORT`:
Set instana-agent's port that the reporter will used. (Default: ```42699```)

View file

@ -12,16 +12,16 @@ Attach labels to your containers and let Traefik do the rest!
??? example "Configuring Docker & Deploying / Exposing Services"
Enabling the docker provider
```toml tab="File (TOML)"
[providers.docker]
```
```yaml tab="File (YAML)"
providers:
docker: {}
```
```bash tab="CLI"
--providers.docker=true
```
@ -37,6 +37,27 @@ Attach labels to your containers and let Traefik do the rest!
- traefik.http.routers.my-container.rule=Host(`mydomain.com`)
```
??? example "Specify a Custom Port for the Container"
Forward requests for `http://mydomain.com` to `http://<private IP of container>:12345`:
```yaml
version: "3"
services:
my-container:
# ...
labels:
- traefik.http.routers.my-container.rule=Host(`mydomain.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 "Configuring Docker Swarm & Deploying / Exposing Services"
Enabling the docker provider (Swarm Mode)
@ -49,7 +70,7 @@ Attach labels to your containers and let Traefik do the rest!
endpoint = "tcp://127.0.0.1:2377"
swarmMode = true
```
```yaml tab="File (YAML)"
providers:
docker:
@ -59,7 +80,7 @@ Attach labels to your containers and let Traefik do the rest!
endpoint: "tcp://127.0.0.1:2375"
swarmMode: true
```
```bash tab="CLI"
--providers.docker.endpoint="tcp://127.0.0.1:2375"
--providers.docker.swarmMode=true
@ -85,7 +106,7 @@ Attach labels to your containers and let Traefik do the rest!
## Routing Configuration
!!! info "Labels"
- Labels are case insensitive.
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md).
@ -129,82 +150,84 @@ add labels starting with `traefik.http.routers.<name-of-your-choice>.` and follo
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`mydomain.com`)```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
See [rule](../routers/index.md#rule) for more information.
```yaml
- "traefik.http.routers.myrouter.rule=Host(`mydomain.com`)"
```
??? info "`traefik.http.routers.<router_name>.entrypoints`"
See [entry points](../routers/index.md#entrypoints) for more information.
See [entry points](../routers/index.md#entrypoints) for more information.
```yaml
- "traefik.http.routers.myrouter.entrypoints=web,websecure"
```
??? info "`traefik.http.routers.<router_name>.middlewares`"
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
```yaml
- "traefik.http.routers.myrouter.middlewares=auth,prefix,cb"
```
??? info "`traefik.http.routers.<router_name>.service`"
See [rule](../routers/index.md#service) for more information.
See [rule](../routers/index.md#service) for more information.
```yaml
- "traefik.http.routers.myrouter.service=myservice"
```
??? info "`traefik.http.routers.<router_name>.tls`"
See [tls](../routers/index.md#tls) for more information.
```yaml
- "traefik.http.routers.myrouter.tls=true"
```
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
See [certResolver](../routers/index.md#certresolver) for more information.
```yaml
- "traefik.http.routers.myrouter.tls.certresolver=myresolver"
```
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
See [domains](../routers/index.md#domains) for more information.
```yaml
- "traefik.http.routers.myrouter.tls.domains[0].main=foobar.com"
```
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
See [domains](../routers/index.md#domains) for more information.
```yaml
- "traefik.http.routers.myrouter.tls.domains[0].sans=test.foobar.com,dev.foobar.com"
```
??? info "`traefik.http.routers.<router_name>.tls.options`"
See [options](../routers/index.md#options) for more information.
```yaml
- "traefik.http.routers.myrouter.tls.options=foobar"
```
??? info "`traefik.http.routers.<router_name>.priority`"
See [options](../routers/index.md#priority) for more information.
See [priority](../routers/index.md#priority) for more information.
```yaml
- "traefik.http.routers.myrouter.priority=42"
```
@ -217,125 +240,127 @@ add labels starting with `traefik.http.services.<name-of-your-choice>.`, followe
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.
```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.passhostheader`"
See [pass Host header](../services/index.md#pass-host-header) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.passhostheader=true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
See [health check](../services/index.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](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.hostname=foobar.com"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
See [health check](../services/index.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](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.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](../services/index.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](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky=true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly=true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
See [response forwarding](../services/index.md#response-forwarding) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
```
@ -350,6 +375,8 @@ you'd write `traefik.http.middlewares.my-redirect.redirectscheme.scheme=https`.
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```yaml
@ -391,73 +418,73 @@ You can declare TCP Routers and/or Services using labels.
#### TCP Routers
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
See [entry points](../routers/index.md#entrypoints_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.entrypoints=ep1,ep2"
```
??? info "`traefik.tcp.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.rule=HostSNI(`myhost.com`)"
```
??? info "`traefik.tcp.routers.<router_name>.service`"
See [service](../routers/index.md#services) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.service=myservice"
```
??? info "`traefik.tcp.routers.<router_name>.tls`"
See [TLS](../routers/index.md#tls_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls=true"
```
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
See [certResolver](../routers/index.md#certresolver_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls.certresolver=myresolver"
```
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
See [domains](../routers/index.md#domains_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls.domains[0].main=foobar.com"
```
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
See [domains](../routers/index.md#domains_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls.domains[0].sans=test.foobar.com,dev.foobar.com"
```
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
See [options](../routers/index.md#options_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls.options=mysoptions"
```
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
See [TLS](../routers/index.md#tls_1) for more information.
```yaml
- "traefik.tcp.routers.mytcprouter.tls.passthrough=true"
```
@ -465,17 +492,17 @@ You can declare TCP Routers and/or Services using labels.
#### 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.terminationdelay`"
See [termination delay](../services/index.md#termination-delay) for more information.
```yaml
- "traefik.tcp.services.mytcpservice.loadbalancer.terminationdelay=100"
```

View file

@ -52,6 +52,8 @@ add labels starting with `traefik.http.routers.{router-name-of-your-choice}.` an
For example, to change the routing rule, you could add the label ```"traefik.http.routers.routername.rule": "Host(`mydomain.com`)"```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
@ -126,7 +128,7 @@ For example, to change the routing rule, you could add the label ```"traefik.htt
??? info "`traefik.http.routers.<router_name>.priority`"
See [options](../routers/index.md#priority) for more information.
See [priority](../routers/index.md#priority) for more information.
```json
"traefik.http.routers.myrouter.priority": "42"
@ -139,6 +141,8 @@ add labels starting with `traefik.http.services.{service-name-of-your-choice}.`,
For example, to change the passHostHeader behavior, you'd add the label `"traefik.http.services.servicename.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.
@ -268,6 +272,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```json

View file

@ -57,6 +57,8 @@ To update the configuration of the Router automatically attached to the containe
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`mydomain.com`)```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
@ -131,7 +133,7 @@ For example, to change the rule, you could add the label ```traefik.http.routers
??? info "`traefik.http.routers.<router_name>.priority`"
See [options](../routers/index.md#priority) for more information.
See [priority](../routers/index.md#priority) for more information.
```yaml
- "traefik.http.routers.myrouter.priority=42"
@ -145,6 +147,8 @@ add labels starting with `traefik.http.services.{name-of-your-choice}.`, followe
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.
@ -274,6 +278,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```yaml

View file

@ -7,9 +7,8 @@ There are, however, exceptions when using label-based configurations:
and a label defines a service (e.g. implicitly through a loadbalancer server port value),
but the router does not specify any service,
then that service is automatically assigned to the router.
1. If a label defines a router (e.g. through a router Rule)
but no service is defined, then a service is automatically created
and assigned to the router.
1. If a label defines a router (e.g. through a router Rule) but no service is defined,
then a service is automatically created and assigned to the router.
!!! info ""
As one would expect, in either of these cases, if in addition a service is specified for the router,

View file

@ -84,6 +84,8 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie
## Configuring HTTP Routers
!!! warning "The character `@` is not authorized in the router name"
### EntryPoints
If not specified, HTTP routers will accept requests from all defined entry points.
@ -203,9 +205,14 @@ If you want to limit the router scope to a set of entry points, set the `entryPo
### Rule
Rules are a set of matchers that determine if a particular request matches specific criteria.
Rules are a set of matchers configured with values, that determine if a particular request matches specific criteria.
If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.
??? 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 as values are [Golang's String Literals](https://golang.org/ref/spec#String_literals).
!!! example "Host is traefik.io"
```toml
@ -337,6 +344,8 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
You can attach a list of [middlewares](../../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.
!!! warning "The character `@` is not authorized in the middleware name."
!!! tip "Middlewares order"
Middlewares are applied in the same order as their declaration in **router**.
@ -376,6 +385,8 @@ but there are exceptions for label-based providers.
See the specific [docker](../providers/docker.md#service-definition), [rancher](../providers/rancher.md#service-definition),
or [marathon](../providers/marathon.md#service-definition) documentation.
!!! warning "The character `@` is not authorized in the middleware name."
!!! important "HTTP routers can only target HTTP services (not TCP services)."
### TLS
@ -624,6 +635,8 @@ The [supported `provider` table](../../https/acme.md#providers) indicates if the
## Configuring TCP Routers
!!! warning "The character `@` is not authorized in the router name"
### General
If both HTTP routers and TCP routers listen to the same entry points, the TCP routers will apply *before* the HTTP routers.

View file

@ -1,4 +1,5 @@
{
"extends": "../../../.markdownlint.json",
"MD024": false
"MD024": false,
"MD046": false
}

View file

@ -5,9 +5,9 @@ Configuring How to Reach the Services
![services](../../assets/img/services.png)
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
## Configuration Example
## Configuration Examples
??? example "Declaring an HTTP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
@ -17,11 +17,11 @@ The `Services` are responsible for configuring how to reach the actual services
[http.services.my-service.loadBalancer]
[[http.services.my-service.loadBalancer.servers]]
url = "http://private-ip-server-1/"
url = "http://<private-ip-server-1>:<private-port-server-1>/"
[[http.services.my-service.loadBalancer.servers]]
url = "http://private-ip-server-2/"
url = "http://<private-ip-server-2>:<private-port-server-2>/"
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -29,8 +29,8 @@ The `Services` are responsible for configuring how to reach the actual services
my-service:
loadBalancer:
servers:
- url: "http://private-ip-server-1/"
- url: "http://private-ip-server-2/"
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
- url: "http://<private-ip-server-2>:<private-port-server-2>/"
```
??? example "Declaring a TCP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
@ -40,26 +40,28 @@ The `Services` are responsible for configuring how to reach the actual services
[tcp.services]
[tcp.services.my-service.loadBalancer]
[[tcp.services.my-service.loadBalancer.servers]]
address = "xx.xx.xx.xx:xx"
address = "<private-ip-server-1>:<private-port-server-1>"
[[tcp.services.my-service.loadBalancer.servers]]
address = "xx.xx.xx.xx:xx"
address = "<private-ip-server-2>:<private-port-server-2>"
```
```yaml tab="YAML"
tcp:
services:
my-service:
loadBalancer:
loadBalancer:
servers:
- address: "xx.xx.xx.xx:xx"
- address: "xx.xx.xx.xx:xx"
- address: "<private-ip-server-1>:<private-port-server-1>"
- address: "<private-ip-server-2>:<private-port-server-2>"
```
## Configuring HTTP Services
### Servers Load Balancer
The load balancers are able to load balance the requests between multiple instances of your programs.
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.
??? example "Declaring a Service with Two Servers (with Load Balancing) -- Using the [File Provider](../../providers/file.md)"
@ -87,10 +89,10 @@ The load balancers are able to load balance the requests between multiple instan
#### Servers
Servers declare a single instance of your program.
The `url` option point to a specific instance.
The `url` option point to a specific instance.
!!! info ""
Paths in the servers' `url` have no effect.
Paths in the servers' `url` have no effect.
If you want the requests to be sent to a specific path on your servers,
configure your [`routers`](../routers/index.md) to use a corresponding [middleware](../../middlewares/overview.md) (e.g. the [AddPrefix](../../middlewares/addprefix.md) or [ReplacePath](../../middlewares/replacepath.md)) middlewares.
@ -103,7 +105,7 @@ The `url` option point to a specific instance.
[[http.services.my-service.loadBalancer.servers]]
url = "http://private-ip-server-1/"
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -142,21 +144,21 @@ For now, only round robin load balancing is supported:
```
#### Sticky sessions
When sticky sessions are enabled, a cookie is set on the initial request to track which server handles the first response.
On subsequent requests, the client is forwarded to the same server.
!!! info "Stickiness & Unhealthy Servers"
If the server specified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server).
!!! info "Cookie Name"
!!! info "Cookie Name"
The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`).
!!! info "Secure & HTTPOnly flags"
By default, the affinity cookie is created without those flags. One however can change that through configuration.
By default, the affinity cookie is created without those flags. One however can change that through configuration.
??? example "Adding Stickiness -- Using the [File Provider](../../providers/file.md)"
@ -166,7 +168,7 @@ On subsequent requests, the client is forwarded to the same server.
[http.services.my-service]
[http.services.my-service.loadBalancer.sticky.cookie]
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -223,8 +225,8 @@ Below are the available options for the health check mechanism:
The interval must be greater than the timeout. If configuration doesn't reflect this, the interval will be set to timeout + 1 second.
!!! info "Recovering Servers"
Traefik keeps monitoring the health of unhealthy servers.
Traefik keeps monitoring the health of unhealthy servers.
If a server has recovered (returning `2xx` -> `3xx` responses again), it will be added back to the load balacer rotation pool.
??? example "Custom Interval & Timeout -- Using the [File Provider](../../providers/file.md)"
@ -261,7 +263,7 @@ Below are the available options for the health check mechanism:
path = "/health"
port = 8080
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -283,7 +285,7 @@ Below are the available options for the health check mechanism:
path = "/health"
scheme = "http"
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -308,7 +310,7 @@ Below are the available options for the health check mechanism:
My-Custom-Header = "foo"
My-Header = "bar"
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -337,7 +339,7 @@ By default, `passHostHeader` is true.
[http.services.Service01.loadBalancer]
passHostHeader = false
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -346,7 +348,7 @@ By default, `passHostHeader` is true.
loadBalancer:
passHostHeader: false
```
#### Response Forwarding
This section is about configuring how Traefik forwards the response from the backend server to the client.
@ -358,7 +360,7 @@ Below are the available options for the Response Forwarding mechanism:
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.
??? example "Using a custom FlushInterval -- Using the [File Provider](../../providers/file.md)"
```toml tab="TOML"
@ -368,7 +370,7 @@ Below are the available options for the Response Forwarding mechanism:
[http.services.Service-1.loadBalancer.responseForwarding]
flushInterval = "1s"
```
```yaml tab="YAML"
## Dynamic configuration
http:
@ -378,7 +380,7 @@ Below are the available options for the Response Forwarding mechanism:
responseForwarding:
flushInterval: 1s
```
### Weighted Round Robin (service)
The WRR is able to load balance the requests between multiple services based on weights.
@ -539,7 +541,7 @@ The `address` option (IP:Port) point to a specific instance.
my-service:
loadBalancer:
servers:
address: "xx.xx.xx.xx:xx"
- address: "xx.xx.xx.xx:xx"
```
#### Termination Delay

View file

@ -101,4 +101,4 @@ curl [-k] https://your.domain.com/tls
curl [-k] http://your.domain.com:8000/notls
```
Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not in the root DNS servers.
Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not an authorized certificate authority on systems where it hasn't been manually added.

View file

@ -21,7 +21,7 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
--check_external_hash \
--alt_ignore="/traefik.logo.png/" \
--http_status_ignore="0,500,501,503" \
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/containous\/traefik\/*edit*/,/github.com\/containous\/traefik\/$/,/docs.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/" \
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/containous\/traefik\/*edit*/,/github.com\/containous\/traefik\/$/,/docs.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/" \
'{}' 1>/dev/null
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration

View file

@ -1,5 +1,5 @@
# WEBUI
FROM node:8.15.0 as webui
FROM node:12.11 as webui
ENV WEBUI_DIR /src/webui
RUN mkdir -p $WEBUI_DIR
@ -7,7 +7,7 @@ RUN mkdir -p $WEBUI_DIR
COPY ./webui/ $WEBUI_DIR/
WORKDIR $WEBUI_DIR
RUN yarn install
RUN npm install
RUN npm run build

View file

@ -973,6 +973,11 @@ func (in *ServersLoadBalancer) DeepCopyInto(out *ServersLoadBalancer) {
*out = new(HealthCheck)
(*in).DeepCopyInto(*out)
}
if in.PassHostHeader != nil {
in, out := &in.PassHostHeader, &out.PassHostHeader
*out = new(bool)
**out = **in
}
if in.ResponseForwarding != nil {
in, out := &in.ResponseForwarding, &out.ResponseForwarding
*out = new(ResponseForwarding)

View file

@ -1,123 +0,0 @@
package hostresolver
import (
"fmt"
"net"
"sort"
"strings"
"time"
"github.com/containous/traefik/v2/pkg/log"
"github.com/miekg/dns"
"github.com/patrickmn/go-cache"
)
type cnameResolv struct {
TTL time.Duration
Record string
}
type byTTL []*cnameResolv
func (a byTTL) Len() int { return len(a) }
func (a byTTL) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byTTL) Less(i, j int) bool { return a[i].TTL > a[j].TTL }
// Resolver used for host resolver
type Resolver struct {
CnameFlattening bool
ResolvConfig string
ResolvDepth int
cache *cache.Cache
}
// CNAMEFlatten check if CNAME record exists, flatten if possible
func (hr *Resolver) CNAMEFlatten(host string) (string, string) {
if hr.cache == nil {
hr.cache = cache.New(30*time.Minute, 5*time.Minute)
}
result := []string{host}
request := host
value, found := hr.cache.Get(host)
if found {
result = strings.Split(value.(string), ",")
} else {
var cacheDuration = 0 * time.Second
for depth := 0; depth < hr.ResolvDepth; depth++ {
resolv, err := cnameResolve(request, hr.ResolvConfig)
if err != nil {
log.Error(err)
break
}
if resolv == nil {
break
}
result = append(result, resolv.Record)
if depth == 0 {
cacheDuration = resolv.TTL
}
request = resolv.Record
}
if err := hr.cache.Add(host, strings.Join(result, ","), cacheDuration); err != nil {
log.Error(err)
}
}
return result[0], result[len(result)-1]
}
// cnameResolve resolves CNAME if exists, and return with the highest TTL
func cnameResolve(host string, resolvPath string) (*cnameResolv, error) {
config, err := dns.ClientConfigFromFile(resolvPath)
if err != nil {
return nil, fmt.Errorf("invalid resolver configuration file: %s", resolvPath)
}
client := &dns.Client{Timeout: 30 * time.Second}
m := &dns.Msg{}
m.SetQuestion(dns.Fqdn(host), dns.TypeCNAME)
var result []*cnameResolv
for _, server := range config.Servers {
tempRecord, err := getRecord(client, m, server, config.Port)
if err != nil {
log.Errorf("Failed to resolve host %s: %v", host, err)
continue
}
result = append(result, tempRecord)
}
if len(result) == 0 {
return nil, nil
}
sort.Sort(byTTL(result))
return result[0], nil
}
func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) {
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
if err != nil {
return nil, fmt.Errorf("exchange error for server %s: %v", server, err)
}
if resp == nil || len(resp.Answer) == 0 {
return nil, fmt.Errorf("empty answer for server %s", server)
}
rr, ok := resp.Answer[0].(*dns.CNAME)
if !ok {
return nil, fmt.Errorf("invalid response type for server %s", server)
}
return &cnameResolv{
TTL: time.Duration(rr.Hdr.Ttl) * time.Second,
Record: strings.TrimSuffix(rr.Target, "."),
}, nil
}

View file

@ -1,61 +0,0 @@
package hostresolver
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCNAMEFlatten(t *testing.T) {
testCase := []struct {
desc string
resolvFile string
domain string
expectedDomain string
isCNAME bool
}{
{
desc: "host request is CNAME record",
resolvFile: "/etc/resolv.conf",
domain: "www.github.com",
expectedDomain: "github.com",
isCNAME: true,
},
{
desc: "resolve file not found",
resolvFile: "/etc/resolv.oops",
domain: "www.github.com",
expectedDomain: "www.github.com",
isCNAME: false,
},
{
desc: "host request is not CNAME record",
resolvFile: "/etc/resolv.conf",
domain: "github.com",
expectedDomain: "github.com",
isCNAME: false,
},
}
for _, test := range testCase {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
hostResolver := &Resolver{
ResolvConfig: test.resolvFile,
ResolvDepth: 5,
}
reqH, flatH := hostResolver.CNAMEFlatten(test.domain)
assert.Equal(t, test.domain, reqH)
assert.Equal(t, test.expectedDomain, flatH)
if test.isCNAME {
assert.NotEqual(t, test.expectedDomain, reqH)
} else {
assert.Equal(t, test.expectedDomain, reqH)
}
})
}
}

View file

@ -3,6 +3,7 @@ package accesslog
import (
"context"
"fmt"
"io"
"net"
"net/http"
"net/url"
@ -31,6 +32,19 @@ const (
JSONFormat string = "json"
)
type noopCloser struct {
*os.File
}
func (n noopCloser) Write(p []byte) (int, error) {
return n.File.Write(p)
}
func (n noopCloser) Close() error {
// noop
return nil
}
type handlerParams struct {
logDataTable *LogData
crr *captureRequestReader
@ -41,7 +55,7 @@ type handlerParams struct {
type Handler struct {
config *types.AccessLog
logger *logrus.Logger
file *os.File
file io.WriteCloser
mu sync.Mutex
httpCodeRanges types.HTTPCodeRanges
logHandlerChan chan handlerParams
@ -59,7 +73,7 @@ func WrapHandler(handler *Handler) alice.Constructor {
// NewHandler creates a new Handler.
func NewHandler(config *types.AccessLog) (*Handler, error) {
file := os.Stdout
var file io.WriteCloser = noopCloser{os.Stdout}
if len(config.FilePath) > 0 {
f, err := openAccessLogFile(config.FilePath)
if err != nil {
@ -213,14 +227,15 @@ func (h *Handler) Close() error {
// Rotate closes and reopens the log file to allow for rotation by an external source.
func (h *Handler) Rotate() error {
var err error
if h.file != nil {
defer func(f *os.File) {
f.Close()
}(h.file)
if h.config.FilePath == "" {
return nil
}
if h.file != nil {
defer func(f io.Closer) { _ = f.Close() }(h.file)
}
var err error
h.file, err = os.OpenFile(h.config.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
if err != nil {
return err

View file

@ -22,7 +22,10 @@ import (
)
// Compile time validation that the response recorder implements http interfaces correctly.
var _ middlewares.Stateful = &responseRecorderWithCloseNotify{}
var (
_ middlewares.Stateful = &responseRecorderWithCloseNotify{}
_ middlewares.Stateful = &codeCatcherWithCloseNotify{}
)
const (
typeName = "customError"
@ -80,25 +83,29 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
recorder := newResponseRecorder(ctx, rw)
c.next.ServeHTTP(recorder, req)
catcher := newCodeCatcher(rw, c.httpCodeRanges)
c.next.ServeHTTP(catcher, req)
if !catcher.isFilteredCode() {
return
}
// check the recorder code against the configured http status code ranges
code := catcher.getCode()
for _, block := range c.httpCodeRanges {
if recorder.GetCode() >= block[0] && recorder.GetCode() <= block[1] {
logger.Errorf("Caught HTTP Status Code %d, returning error page", recorder.GetCode())
if code >= block[0] && code <= block[1] {
logger.Errorf("Caught HTTP Status Code %d, returning error page", code)
var query string
if len(c.backendQuery) > 0 {
query = "/" + strings.TrimPrefix(c.backendQuery, "/")
query = strings.Replace(query, "{status}", strconv.Itoa(recorder.GetCode()), -1)
query = strings.Replace(query, "{status}", strconv.Itoa(code), -1)
}
pageReq, err := newRequest(backendURL + query)
if err != nil {
logger.Error(err)
rw.WriteHeader(recorder.GetCode())
_, err = fmt.Fprint(rw, http.StatusText(recorder.GetCode()))
rw.WriteHeader(code)
_, err = fmt.Fprint(rw, http.StatusText(code))
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
@ -111,7 +118,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context()))
utils.CopyHeaders(rw.Header(), recorderErrorPage.Header())
rw.WriteHeader(recorder.GetCode())
rw.WriteHeader(code)
if _, err = rw.Write(recorderErrorPage.GetBody().Bytes()); err != nil {
logger.Error(err)
@ -119,14 +126,6 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
}
// did not catch a configured status code so proceed with the request
utils.CopyHeaders(rw.Header(), recorder.Header())
rw.WriteHeader(recorder.GetCode())
_, err := rw.Write(recorder.GetBody().Bytes())
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func newRequest(baseURL string) (*http.Request, error) {
@ -144,6 +143,132 @@ func newRequest(baseURL string) (*http.Request, error) {
return req, nil
}
type responseInterceptor interface {
http.ResponseWriter
http.Flusher
getCode() int
isFilteredCode() bool
}
// codeCatcher is a response writer that detects as soon as possible whether the
// response is a code within the ranges of codes it watches for. If it is, it
// simply drops the data from the response. Otherwise, it forwards it directly to
// the original client (its responseWriter) without any buffering.
type codeCatcher struct {
headerMap http.Header
code int
httpCodeRanges types.HTTPCodeRanges
firstWrite bool
caughtFilteredCode bool
responseWriter http.ResponseWriter
headersSent bool
}
type codeCatcherWithCloseNotify struct {
*codeCatcher
}
// CloseNotify returns a channel that receives at most a
// single value (true) when the client connection has gone away.
func (cc *codeCatcherWithCloseNotify) CloseNotify() <-chan bool {
return cc.responseWriter.(http.CloseNotifier).CloseNotify()
}
func newCodeCatcher(rw http.ResponseWriter, httpCodeRanges types.HTTPCodeRanges) responseInterceptor {
catcher := &codeCatcher{
headerMap: make(http.Header),
code: http.StatusOK, // If backend does not call WriteHeader on us, we consider it's a 200.
responseWriter: rw,
httpCodeRanges: httpCodeRanges,
firstWrite: true,
}
if _, ok := rw.(http.CloseNotifier); ok {
return &codeCatcherWithCloseNotify{catcher}
}
return catcher
}
func (cc *codeCatcher) Header() http.Header {
if cc.headerMap == nil {
cc.headerMap = make(http.Header)
}
return cc.headerMap
}
func (cc *codeCatcher) getCode() int {
return cc.code
}
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
// and for which the response should be deferred to the error handler.
func (cc *codeCatcher) isFilteredCode() bool {
return cc.caughtFilteredCode
}
func (cc *codeCatcher) Write(buf []byte) (int, error) {
if !cc.firstWrite {
if cc.caughtFilteredCode {
// We don't care about the contents of the response,
// since we want to serve the ones from the error page,
// so we just drop them.
return len(buf), nil
}
return cc.responseWriter.Write(buf)
}
cc.firstWrite = false
// If WriteHeader was already called from the caller, this is a NOOP.
// Otherwise, cc.code is actually a 200 here.
cc.WriteHeader(cc.code)
if cc.caughtFilteredCode {
return len(buf), nil
}
return cc.responseWriter.Write(buf)
}
func (cc *codeCatcher) WriteHeader(code int) {
if cc.headersSent || cc.caughtFilteredCode {
return
}
cc.code = code
for _, block := range cc.httpCodeRanges {
if cc.code >= block[0] && cc.code <= block[1] {
cc.caughtFilteredCode = true
break
}
}
// it will be up to the other response recorder to send the headers,
// so it is out of our hands now.
if cc.caughtFilteredCode {
return
}
utils.CopyHeaders(cc.responseWriter.Header(), cc.Header())
cc.responseWriter.WriteHeader(cc.code)
cc.headersSent = true
}
// Hijack hijacks the connection
func (cc *codeCatcher) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hj, ok := cc.responseWriter.(http.Hijacker); ok {
return hj.Hijack()
}
return nil, nil, fmt.Errorf("%T is not a http.Hijacker", cc.responseWriter)
}
// Flush sends any buffered data to the client.
func (cc *codeCatcher) Flush() {
// If WriteHeader was already called from the caller, this is a NOOP.
// Otherwise, cc.code is actually a 200 here.
cc.WriteHeader(cc.code)
if flusher, ok := cc.responseWriter.(http.Flusher); ok {
flusher.Flush()
}
}
type responseRecorder interface {
http.ResponseWriter
http.Flusher

View file

@ -33,6 +33,30 @@ func TestHandler(t *testing.T) {
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusOK))
},
},
{
desc: "no error, but not a 200",
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
backendCode: http.StatusPartialContent,
backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "My error page.")
}),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusPartialContent, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), http.StatusText(http.StatusPartialContent))
},
},
{
desc: "a 304, so no Write called",
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
backendCode: http.StatusNotModified,
backendErrorHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "whatever, should not be called")
}),
validate: func(t *testing.T, recorder *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusNotModified, recorder.Code, "HTTP status")
assert.Contains(t, recorder.Body.String(), "")
},
},
{
desc: "in the range",
errorPage: &dynamic.ErrorPage{Service: "error", Query: "/test", Status: []string{"500-501", "503-599"}},
@ -104,6 +128,9 @@ func TestHandler(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(test.backendCode)
if test.backendCode == http.StatusNotModified {
return
}
fmt.Fprintln(w, http.StatusText(test.backendCode))
})
errorPageHandler, err := New(context.Background(), handler, *test.errorPage, serviceBuilderMock, "test")

View file

@ -3,6 +3,7 @@ package recovery
import (
"context"
"net/http"
"runtime"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/middlewares"
@ -28,13 +29,30 @@ func New(ctx context.Context, next http.Handler, name string) (http.Handler, err
}
func (re *recovery) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
defer recoverFunc(middlewares.GetLoggerCtx(req.Context(), re.name, typeName), rw)
defer recoverFunc(middlewares.GetLoggerCtx(req.Context(), re.name, typeName), rw, req)
re.next.ServeHTTP(rw, req)
}
func recoverFunc(ctx context.Context, rw http.ResponseWriter) {
func recoverFunc(ctx context.Context, rw http.ResponseWriter, r *http.Request) {
if err := recover(); err != nil {
log.FromContext(ctx).Errorf("Recovered from panic in http handler: %+v", err)
if !shouldLogPanic(err) {
log.FromContext(ctx).Debugf("Request has been aborted [%s - %s]: %v", r.RemoteAddr, r.URL, err)
return
}
log.FromContext(ctx).Errorf("Recovered from panic in HTTP handler [%s - %s]: %+v", r.RemoteAddr, r.URL, err)
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
log.FromContext(ctx).Errorf("Stack: %s", buf)
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
}
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
func shouldLogPanic(panicValue interface{}) bool {
return panicValue != nil && panicValue != http.ErrAbortHandler
}

View file

@ -323,7 +323,7 @@ func (p *Provider) resolveDomains(ctx context.Context, domains []string, tlsStor
return
}
log.FromContext(ctx).Debugf("Try to challenge certificate for domain %v founded in HostSNI rule", domains)
log.FromContext(ctx).Debugf("Try to challenge certificate for domain %v found in HostSNI rule", domains)
var domain types.Domain
if len(domains) > 0 {

View file

@ -199,8 +199,6 @@ func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguratio
}
func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory string, configuration *dynamic.Configuration) (*dynamic.Configuration, error) {
logger := log.FromContext(ctx)
fileList, err := ioutil.ReadDir(directory)
if err != nil {
return configuration, fmt.Errorf("unable to read directory %s: %v", directory, err)
@ -227,6 +225,8 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
configTLSMaps := make(map[*tls.CertAndStores]struct{})
for _, item := range fileList {
logger := log.FromContext(log.With(ctx, log.Str("filename", item.Name())))
if item.IsDir() {
configuration, err = p.loadFileConfigFromDirectory(ctx, filepath.Join(directory, item.Name()), configuration)
if err != nil {
@ -245,7 +245,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
var c *dynamic.Configuration
c, err = p.loadFileConfig(ctx, filepath.Join(directory, item.Name()), true)
if err != nil {
return configuration, err
return configuration, fmt.Errorf("%s: %v", filepath.Join(directory, item.Name()), err)
}
for name, conf := range c.HTTP.Routers {

View file

@ -7,7 +7,6 @@ import (
"crypto/sha256"
"fmt"
"os"
"reflect"
"sort"
"strconv"
"strings"
@ -21,6 +20,7 @@ import (
"github.com/containous/traefik/v2/pkg/safe"
"github.com/containous/traefik/v2/pkg/tls"
"github.com/containous/traefik/v2/pkg/types"
"github.com/mitchellh/hashstructure"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
)
@ -127,10 +127,14 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
// track more information about the dropped events.
conf := p.loadConfigurationFromCRD(ctxLog, k8sClient)
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
confHash, err := hashstructure.Hash(conf, nil)
switch {
case err != nil:
logger.Error("Unable to hash the configuration")
case p.lastConfiguration.Get() == confHash:
logger.Debugf("Skipping Kubernetes event kind %T", event)
} else {
p.lastConfiguration.Set(conf)
default:
p.lastConfiguration.Set(confHash)
configurationChan <- dynamic.Message{
ProviderName: "kubernetescrd",
Configuration: conf,

View file

@ -209,8 +209,13 @@ func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynam
var servers []dynamic.Server
if service.Spec.Type == corev1.ServiceTypeExternalName {
protocol := "http"
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
protocol = "https"
}
servers = append(servers, dynamic.Server{
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
})
} else {
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)

View file

@ -6,7 +6,6 @@ import (
"fmt"
"math"
"os"
"reflect"
"sort"
"strconv"
"strings"
@ -16,9 +15,11 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/job"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/provider"
"github.com/containous/traefik/v2/pkg/safe"
"github.com/containous/traefik/v2/pkg/tls"
"github.com/containous/traefik/v2/pkg/types"
"github.com/mitchellh/hashstructure"
corev1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/labels"
@ -138,10 +139,14 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
// track more information about the dropped events.
conf := p.loadConfigurationFromIngresses(ctxLog, k8sClient)
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
confHash, err := hashstructure.Hash(conf, nil)
switch {
case err != nil:
logger.Error("Unable to hash the configuration")
case p.lastConfiguration.Get() == confHash:
logger.Debugf("Skipping Kubernetes event kind %T", event)
} else {
p.lastConfiguration.Set(conf)
default:
p.lastConfiguration.Set(confHash)
configurationChan <- dynamic.Message{
ProviderName: "kubernetes",
Configuration: conf,
@ -202,8 +207,13 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
}
if service.Spec.Type == corev1.ServiceTypeExternalName {
protocol := "http"
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
protocol = "https"
}
servers = append(servers, dynamic.Server{
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
})
} else {
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, backend.ServiceName)
@ -324,8 +334,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
continue
}
serviceName := ingress.Namespace + "-" + p.Backend.ServiceName + "-" + p.Backend.ServicePort.String()
serviceName = strings.ReplaceAll(serviceName, ".", "-")
serviceName := provider.Normalize(ingress.Namespace + "-" + p.Backend.ServiceName + "-" + p.Backend.ServicePort.String())
var rules []string
if len(rule.Host) > 0 {
rules = []string{"Host(`" + rule.Host + "`)"}
@ -335,10 +344,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
rules = append(rules, "PathPrefix(`"+p.Path+"`)")
}
routerKey := strings.Replace(rule.Host, ".", "-", -1) + strings.Replace(p.Path, "/", "-", 1)
if strings.HasPrefix(routerKey, "-") {
routerKey = strings.Replace(routerKey, "-", "", 1)
}
routerKey := strings.TrimPrefix(provider.Normalize(rule.Host+p.Path), "-")
conf.HTTP.Routers[routerKey] = &dynamic.Router{
Rule: strings.Join(rules, " && "),
Service: serviceName,

View file

@ -94,8 +94,9 @@ func setupTracing(conf *static.Tracing) tracing.Backend {
if backend == nil {
log.WithoutContext().Debug("Could not initialize tracing, use Jaeger by default")
backend := &jaeger.Config{}
backend.SetDefaults()
bcd := &jaeger.Config{}
bcd.SetDefaults()
backend = bcd
}
return backend

View file

@ -254,6 +254,15 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
return tc, nil
}
type proxyProtocolLogger struct {
log.Logger
}
// Printf force log level to debug.
func (p proxyProtocolLogger) Printf(format string, v ...interface{}) {
p.Debugf(format, v...)
}
func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoint, listener net.Listener) (net.Listener, error) {
var sourceCheck func(addr net.Addr) (bool, error)
if entryPoint.ProxyProtocol.Insecure {
@ -280,7 +289,7 @@ func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoi
return proxyprotocol.NewDefaultListener(listener).
WithSourceChecker(sourceCheck).
WithLogger(log.FromContext(ctx)), nil
WithLogger(proxyProtocolLogger{Logger: log.FromContext(ctx)}), nil
}
func buildListener(ctx context.Context, entryPoint *static.EntryPoint) (net.Listener, error) {

View file

@ -189,7 +189,7 @@ func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certifi
}
}
if certExists {
log.Warnf("Skipping addition of certificate for domain(s) %q, to EntryPoint %s, as it already exists for this Entrypoint.", certKey, ep)
log.Debugf("Skipping addition of certificate for domain(s) %q, to EntryPoint %s, as it already exists for this Entrypoint.", certKey, ep)
} else {
log.Debugf("Adding certificate for domain(s) %s", certKey)
certs[ep][certKey] = &tlsCert

View file

@ -86,6 +86,7 @@ func derCert(privKey *rsa.PrivateKey, expiration time.Time, domain string) ([]by
NotAfter: expiration,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageDataEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
DNSNames: []string{domain},
}

View file

@ -20,7 +20,6 @@ type Config struct {
// SetDefaults sets the default values.
func (c *Config) SetDefaults() {
c.LocalAgentHost = "localhost"
c.LocalAgentPort = 42699
c.LogLevel = "info"
}

View file

@ -28,7 +28,7 @@ fi
# Build binaries
# shellcheck disable=SC2086
CGO_ENABLED=0 GOGC=off go build ${FLAGS[*]} -ldflags "-s -w \
-X github.com/containous/traefik/pkg/v2/version.Version=$VERSION \
-X github.com/containous/traefik/pkg/v2/version.Codename=$CODENAME \
-X github.com/containous/traefik/pkg/v2/version.BuildDate=$DATE" \
-X github.com/containous/traefik/v2/pkg/version.Version=$VERSION \
-X github.com/containous/traefik/v2/pkg/version.Codename=$CODENAME \
-X github.com/containous/traefik/v2/pkg/version.BuildDate=$DATE" \
-a -installsuffix nocgo -o dist/traefik ./cmd/traefik

View file

@ -1,4 +1,4 @@
FROM node:8.15.0
FROM node:12.11
ENV WEBUI_DIR /src/webui
RUN mkdir -p $WEBUI_DIR

View file

@ -20,7 +20,7 @@ make generate-webui # Generate static contents in `traefik/static/` folder.
## How to build (only for frontend developer)
- prerequisite: [Node 6+](https://nodejs.org) [Npm](https://www.npmjs.com/)
- prerequisite: [Node 12.11+](https://nodejs.org) [Npm](https://www.npmjs.com/)
- Go to the directory `webui`