Merge tag 'v1.7.4' into master
This commit is contained in:
commit
d3ae88f108
154 changed files with 4356 additions and 1285 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,5 +1,40 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [v1.7.4](https://github.com/containous/traefik/tree/v1.7.4) (2018-10-30)
|
||||||
|
[All Commits](https://github.com/containous/traefik/compare/v1.7.3...v1.7.4)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[acme]** Support custom DNS resolvers for Let's Encrypt. ([#4101](https://github.com/containous/traefik/pull/4101) by [ldez](https://github.com/ldez))
|
||||||
|
- **[acme]** fix: netcup and DuckDNS. ([#4094](https://github.com/containous/traefik/pull/4094) by [ldez](https://github.com/ldez))
|
||||||
|
- **[authentication,logs,middleware]** Fix display of client username field ([#4093](https://github.com/containous/traefik/pull/4093) by [Ullaakut](https://github.com/Ullaakut))
|
||||||
|
- **[authentication,middleware]** Nil request body with retry ([#4075](https://github.com/containous/traefik/pull/4075) by [ldez](https://github.com/ldez))
|
||||||
|
- **[consul,consulcatalog,docker,ecs,k8s,marathon,mesos,rancher]** Add flush interval option on backend ([#4112](https://github.com/containous/traefik/pull/4112) by [juliens](https://github.com/juliens))
|
||||||
|
- **[consulcatalog,docker,ecs,marathon,mesos,rancher]** Remove the trailing dot if the domain is not defined. ([#4095](https://github.com/containous/traefik/pull/4095) by [ldez](https://github.com/ldez))
|
||||||
|
- **[docker]** Provider docker shutdown problem ([#4122](https://github.com/containous/traefik/pull/4122) by [juliens](https://github.com/juliens))
|
||||||
|
- **[k8s]** Add default path if nothing present ([#4097](https://github.com/containous/traefik/pull/4097) by [SantoDE](https://github.com/SantoDE))
|
||||||
|
- **[k8s]** Add the missing pass-client-tls annotation to the kubernetes provider ([#4118](https://github.com/containous/traefik/pull/4118) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||||
|
- **[logs]** Fix access log field parsing ([#4113](https://github.com/containous/traefik/pull/4113) by [Ullaakut](https://github.com/Ullaakut))
|
||||||
|
- **[middleware]** Add static redirect ([#4090](https://github.com/containous/traefik/pull/4090) by [SantoDE](https://github.com/SantoDE))
|
||||||
|
- **[rules]** Add keepTrailingSlash option ([#4062](https://github.com/containous/traefik/pull/4062) by [juliens](https://github.com/juliens))
|
||||||
|
- **[rules]** Case insensitive host rule ([#3931](https://github.com/containous/traefik/pull/3931) by [bgandon](https://github.com/bgandon))
|
||||||
|
- **[tls]** Fix certificate insertion loop to keep valid certificate and ignore the bad one ([#4050](https://github.com/containous/traefik/pull/4050) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||||
|
- **[webui]** Typo in the UI. ([#4096](https://github.com/containous/traefik/pull/4096) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[acme]** Adds the note: acme.domains is a startup configuration ([#4065](https://github.com/containous/traefik/pull/4065) by [geraldcroes](https://github.com/geraldcroes))
|
||||||
|
- **[acme]** exoscale move from .ch to .com ([#4130](https://github.com/containous/traefik/pull/4130) by [greut](https://github.com/greut))
|
||||||
|
- **[acme]** Fixing a typo. ([#4124](https://github.com/containous/traefik/pull/4124) by [konovalov-nk](https://github.com/konovalov-nk))
|
||||||
|
- **[acme]** Add a note about TLS-ALPN challenge. ([#4106](https://github.com/containous/traefik/pull/4106) by [ldez](https://github.com/ldez))
|
||||||
|
- **[acme]** Clarify DuckDNS does not support multiple TXT records ([#4061](https://github.com/containous/traefik/pull/4061) by [KnicKnic](https://github.com/KnicKnic))
|
||||||
|
- **[docker]** Domain is also optional for "normal" mode ([#4086](https://github.com/containous/traefik/pull/4086) by [herver](https://github.com/herver))
|
||||||
|
- **[provider]** Fix mistake in the documentation of several backends ([#4133](https://github.com/containous/traefik/pull/4133) by [whalehub](https://github.com/whalehub))
|
||||||
|
- Replaces emilevauge/whoami by containous/whoami in the documentation ([#4111](https://github.com/containous/traefik/pull/4111) by [geraldcroes](https://github.com/geraldcroes))
|
||||||
|
- Uses ASCII characters to spell Traefik ([#4063](https://github.com/containous/traefik/pull/4063) by [geraldcroes](https://github.com/geraldcroes))
|
||||||
|
|
||||||
|
**Misc:**
|
||||||
|
- **[tls]** Add double wildcard test ([#4091](https://github.com/containous/traefik/pull/4091) by [dtomcej](https://github.com/dtomcej))
|
||||||
|
- **[webui]** Removed unused imports ([#4123](https://github.com/containous/traefik/pull/4123) by [mwvdev](https://github.com/mwvdev))
|
||||||
|
|
||||||
## [v1.7.3](https://github.com/containous/traefik/tree/v1.7.3) (2018-10-15)
|
## [v1.7.3](https://github.com/containous/traefik/tree/v1.7.3) (2018-10-15)
|
||||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.2...v1.7.3)
|
[All Commits](https://github.com/containous/traefik/compare/v1.7.2...v1.7.3)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ traefik*
|
||||||
##### Setting up your `go` environment
|
##### Setting up your `go` environment
|
||||||
|
|
||||||
- You need `go` v1.9+
|
- You need `go` v1.9+
|
||||||
- It is recommended you clone Træfik into a directory like `~/go/src/github.com/containous/traefik` (This is the official golang workspace hierarchy, and will allow dependencies to resolve properly)
|
- It is recommended you clone Traefik into a directory like `~/go/src/github.com/containous/traefik` (This is the official golang workspace hierarchy, and will allow dependencies to resolve properly)
|
||||||
- Set your `GOPATH` and `PATH` variable to be set to `~/go` via:
|
- Set your `GOPATH` and `PATH` variable to be set to `~/go` via:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -56,9 +56,9 @@ GORACE=""
|
||||||
## more go env's will be listed
|
## more go env's will be listed
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Build Træfik
|
##### Build Traefik
|
||||||
|
|
||||||
Once your environment is set up and the Træfik repository cloned you can build Træfik. You need get `go-bindata` once to be able to use `go generate` command as part of the build. The steps to build are:
|
Once your environment is set up and the Traefik repository cloned you can build Traefik. You need get `go-bindata` once to be able to use `go generate` command as part of the build. The steps to build are:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/go/src/github.com/containous/traefik
|
cd ~/go/src/github.com/containous/traefik
|
||||||
|
@ -77,7 +77,7 @@ go build ./cmd/traefik
|
||||||
# run other commands like tests
|
# run other commands like tests
|
||||||
```
|
```
|
||||||
|
|
||||||
You will find the Træfik executable in the `~/go/src/github.com/containous/traefik` folder as `traefik`.
|
You will find the Traefik executable in the `~/go/src/github.com/containous/traefik` folder as `traefik`.
|
||||||
|
|
||||||
### Updating the templates
|
### Updating the templates
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,5 @@ FROM scratch
|
||||||
COPY script/ca-certificates.crt /etc/ssl/certs/
|
COPY script/ca-certificates.crt /etc/ssl/certs/
|
||||||
COPY dist/traefik /
|
COPY dist/traefik /
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
VOLUME ["/tmp"]
|
||||||
ENTRYPOINT ["/traefik"]
|
ENTRYPOINT ["/traefik"]
|
||||||
|
|
33
Gopkg.lock
generated
33
Gopkg.lock
generated
|
@ -49,6 +49,7 @@
|
||||||
"autorest",
|
"autorest",
|
||||||
"autorest/adal",
|
"autorest/adal",
|
||||||
"autorest/azure",
|
"autorest/azure",
|
||||||
|
"autorest/azure/auth",
|
||||||
"autorest/date",
|
"autorest/date",
|
||||||
"autorest/to"
|
"autorest/to"
|
||||||
]
|
]
|
||||||
|
@ -289,7 +290,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/containous/mux"
|
name = "github.com/containous/mux"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "06ccd3e75091eb659b1d720cda0e16bc7057954c"
|
revision = "c33f32e268983f989290677351b871b65da75ba5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/containous/staert"
|
name = "github.com/containous/staert"
|
||||||
|
@ -352,6 +353,12 @@
|
||||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||||
version = "v3.2.0"
|
version = "v3.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/dimchansky/utfbom"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "5448fe645cb1964ba70ac8f9f2ffe975e61a536c"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/dnsimple/dnsimple-go"
|
name = "github.com/dnsimple/dnsimple-go"
|
||||||
|
@ -522,19 +529,6 @@
|
||||||
revision = "44cc805cf13205b55f69e14bcb69867d1ae92f98"
|
revision = "44cc805cf13205b55f69e14bcb69867d1ae92f98"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/edeckers/auroradnsclient"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"records",
|
|
||||||
"requests",
|
|
||||||
"requests/errors",
|
|
||||||
"tokens",
|
|
||||||
"zones"
|
|
||||||
]
|
|
||||||
revision = "1563e622aaca0a8bb895a448f31d4a430ab97586"
|
|
||||||
version = "v1.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/elazarl/go-bindata-assetfs"
|
name = "github.com/elazarl/go-bindata-assetfs"
|
||||||
|
@ -814,6 +808,7 @@
|
||||||
revision = "9b66602d496a139e4722bdde32f0f1ac1c12d4a8"
|
revision = "9b66602d496a139e4722bdde32f0f1ac1c12d4a8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/jjcollinge/servicefabric"
|
name = "github.com/jjcollinge/servicefabric"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
|
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
|
||||||
|
@ -852,6 +847,12 @@
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/ldez/go-auroradns"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "b40dfcae7c417f8129579362695dc1f3cfe5928d"
|
||||||
|
version = "v2.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/libkermit/compose"
|
name = "github.com/libkermit/compose"
|
||||||
|
@ -1388,7 +1389,7 @@
|
||||||
"providers/dns/vegadns",
|
"providers/dns/vegadns",
|
||||||
"providers/dns/vultr"
|
"providers/dns/vultr"
|
||||||
]
|
]
|
||||||
revision = "160d6fe60303699067faad57dc0b1e147ac499ef"
|
revision = "1151b4e3befc51b7b215179c87791753721dc6d5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -1400,6 +1401,8 @@
|
||||||
"ed25519/internal/edwards25519",
|
"ed25519/internal/edwards25519",
|
||||||
"ocsp",
|
"ocsp",
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
|
"pkcs12",
|
||||||
|
"pkcs12/internal/rc2",
|
||||||
"scrypt",
|
"scrypt",
|
||||||
"ssh/terminal"
|
"ssh/terminal"
|
||||||
]
|
]
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
## PR review process:
|
## PR review process:
|
||||||
|
|
||||||
* The status `needs-design-review` is only used in complex/heavy/tricky PRs.
|
* The status `needs-design-review` is only used in complex/heavy/tricky PRs.
|
||||||
* From `status/1-needs-design-review` to `status/2-needs-review`: 1 design LGTM in comment, by a senior maintainer, if needed.
|
* From `1` to `2`: 1 comment that says “design LGTM” (by a senior maintainer).
|
||||||
* From `status/2-needs-review` to `status/3-needs-merge`: 3 LGTM by any maintainer.
|
* From `2` to `3`: 3 LGTM approvals by any maintainer.
|
||||||
* If needed, a specific maintainer familiar with a particular domain can be requested for the review.
|
* If needed, a specific maintainer familiar with a particular domain can be requested for the review.
|
||||||
* If a PR has been implemented in pair programming, one peer's LGTM goes into the review for free
|
* If a PR has been implemented in pair programming, one peer's LGTM goes into the review for free
|
||||||
* Amending someone else's pull request is authorized only in emergency, if a rebase is needed, or if the initial contributor is silent
|
* Amending someone else's pull request is authorized only in emergency, if a rebase is needed, or if the initial contributor is silent
|
||||||
|
@ -50,20 +50,21 @@ We use [PRM](https://github.com/ldez/prm) to manage locally pull requests.
|
||||||
The maintainer giving the final LGTM must add the `status/3-needs-merge` label to trigger the merge bot.
|
The maintainer giving the final LGTM must add the `status/3-needs-merge` label to trigger the merge bot.
|
||||||
|
|
||||||
By default, a squash-rebase merge will be carried out.
|
By default, a squash-rebase merge will be carried out.
|
||||||
If you want to preserve commits you must add `bot/merge-method-rebase` before `status/3-needs-merge`.
|
To preserve commits, add `bot/merge-method-rebase` before `status/3-needs-merge`.
|
||||||
|
|
||||||
The status `status/4-merge-in-progress` is only for the bot.
|
The status `status/4-merge-in-progress` is only used by the bot.
|
||||||
|
|
||||||
If the bot is not able to perform the merge, the label `bot/need-human-merge` is added.
|
If the bot is not able to perform the merge, the label `bot/need-human-merge` is added.
|
||||||
In this case you must solve conflicts/CI/... and after you only need to remove `bot/need-human-merge`.
|
In such a situation, solve the conflicts/CI/... and then remove the label `bot/need-human-merge`.
|
||||||
|
|
||||||
A maintainer can add `bot/no-merge` on a PR if he want (temporarily) prevent a merge by the bot.
|
To prevent the bot from automatically merging a PR, add the label `bot/no-merge`.
|
||||||
|
|
||||||
`bot/light-review` can be used to decrease required LGTM from 3 to 1 when:
|
The label `bot/light-review` decreases the number of required LGTM from 3 to 1.
|
||||||
|
|
||||||
- vendor updates from previously reviewed PRs
|
This label is used when:
|
||||||
- merges branches into master
|
- Updating the vendors from previously reviewed PRs
|
||||||
- prepare release
|
- Merging branches into the master
|
||||||
|
- Preparing the release
|
||||||
|
|
||||||
|
|
||||||
### [Myrmica Bibikoffi](https://github.com/containous/bibikoffi/)
|
### [Myrmica Bibikoffi](https://github.com/containous/bibikoffi/)
|
||||||
|
@ -84,7 +85,7 @@ A maintainer can add `bot/no-merge` on a PR if he want (temporarily) prevent a m
|
||||||
|
|
||||||
## Labels
|
## Labels
|
||||||
|
|
||||||
If we open/look an issue/PR, we must add a `kind/*`, an `area/*` and a `status/*`.
|
A maintainer that looks at an issue/PR must define its `kind/*`, `area/*`, and `status/*`.
|
||||||
|
|
||||||
### Contributor
|
### Contributor
|
||||||
|
|
||||||
|
@ -96,19 +97,19 @@ If we open/look an issue/PR, we must add a `kind/*`, an `area/*` and a `status/*
|
||||||
### Kind
|
### Kind
|
||||||
|
|
||||||
* `kind/enhancement`: a new or improved feature.
|
* `kind/enhancement`: a new or improved feature.
|
||||||
* `kind/question`: It's a question. **(only for issue)**
|
* `kind/question`: a question. **(only for issue)**
|
||||||
* `kind/proposal`: proposal PR/issues need a public debate.
|
* `kind/proposal`: a proposal that needs to be discussed.
|
||||||
* _Proposal issues_ are design proposal that need to be refined with multiple contributors.
|
* _Proposal issues_ are design proposals
|
||||||
* _Proposal PRs_ are technical prototypes that need to be refined with multiple contributors.
|
* _Proposal PRs_ are technical prototypes that need to be refined with multiple contributors.
|
||||||
|
|
||||||
* `kind/bug/possible`: if we need to analyze to understand if it's a bug or not. **(only for issues)**
|
* `kind/bug/possible`: a possible bug that needs analysis before it is confirmed or fixed. **(only for issues)**
|
||||||
* `kind/bug/confirmed`: we are sure, it's a bug. **(only for issues)**
|
* `kind/bug/confirmed`: a confirmed bug (reproducible). **(only for issues)**
|
||||||
* `kind/bug/fix`: it's a bug fix. **(only for PR)**
|
* `kind/bug/fix`: a bug fix. **(only for PR)**
|
||||||
|
|
||||||
### Resolution
|
### Resolution
|
||||||
|
|
||||||
* `resolution/duplicate`: it's a duplicate issue/PR.
|
* `resolution/duplicate`: a duplicate issue/PR.
|
||||||
* `resolution/declined`: Rule #1 of open-source: no is temporary, yes is forever.
|
* `resolution/declined`: declined (Rule #1 of open-source: no is temporary, yes is forever).
|
||||||
* `WIP`: Work In Progress. **(only for PR)**
|
* `WIP`: Work In Progress. **(only for PR)**
|
||||||
|
|
||||||
### Platform
|
### Platform
|
||||||
|
@ -121,10 +122,10 @@ If we open/look an issue/PR, we must add a `kind/*`, an `area/*` and a `status/*
|
||||||
* `area/api`: Traefik API related.
|
* `area/api`: Traefik API related.
|
||||||
* `area/authentication`: Authentication related.
|
* `area/authentication`: Authentication related.
|
||||||
* `area/cluster`: Traefik clustering related.
|
* `area/cluster`: Traefik clustering related.
|
||||||
* `area/documentation`: regards improving/adding documentation.
|
* `area/documentation`: Documentation related.
|
||||||
* `area/infrastructure`: related to CI or Traefik building scripts.
|
* `area/infrastructure`: CI or Traefik building scripts related.
|
||||||
* `area/healthcheck`: Health-check related.
|
* `area/healthcheck`: Health-check related.
|
||||||
* `area/logs`: Traefik logs related.
|
* `area/logs`: Logs related.
|
||||||
* `area/middleware`: Middleware related.
|
* `area/middleware`: Middleware related.
|
||||||
* `area/middleware/metrics`: Metrics related. (Prometheus, StatsD, ...)
|
* `area/middleware/metrics`: Metrics related. (Prometheus, StatsD, ...)
|
||||||
* `area/middleware/tracing`: Tracing related. (Jaeger, Zipkin, ...)
|
* `area/middleware/tracing`: Tracing related. (Jaeger, Zipkin, ...)
|
||||||
|
@ -160,7 +161,7 @@ If we open/look an issue/PR, we must add a `kind/*`, an `area/*` and a `status/*
|
||||||
|
|
||||||
### PR size
|
### PR size
|
||||||
|
|
||||||
_Automatically set by a bot_
|
__Automatically set by a bot__
|
||||||
|
|
||||||
* `size/S`: small PR.
|
* `size/S`: small PR.
|
||||||
* `size/M`: medium PR.
|
* `size/M`: medium PR.
|
||||||
|
@ -170,8 +171,8 @@ _Automatically set by a bot_
|
||||||
|
|
||||||
The `status/*` labels represent the desired state in the workflow.
|
The `status/*` labels represent the desired state in the workflow.
|
||||||
|
|
||||||
* `status/0-needs-triage`: all new issue or PR have this status. _[bot only]_
|
* `status/0-needs-triage`: all the new issues and PRs have this status. _[bot only]_
|
||||||
* `status/1-needs-design-review`: need a design review. **(only for PR)**
|
* `status/1-needs-design-review`: needs a design review. **(only for PR)**
|
||||||
* `status/2-needs-review`: need a code/documentation review. **(only for PR)**
|
* `status/2-needs-review`: needs a code/documentation review. **(only for PR)**
|
||||||
* `status/3-needs-merge`: ready to merge. **(only for PR)**
|
* `status/3-needs-merge`: ready to merge. **(only for PR)**
|
||||||
* `status/4-merge-in-progress`: merge in progress. _[bot only]_
|
* `status/4-merge-in-progress`: merge is in progress. _[bot only]_
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="docs/img/traefik.logo.png" alt="Træfik" title="Træfik" />
|
<img src="docs/img/traefik.logo.png" alt="Traefik" title="Traefik" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
|
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
|
||||||
|
@ -12,9 +12,9 @@
|
||||||
[![Twitter](https://img.shields.io/twitter/follow/traefik.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefik)
|
[![Twitter](https://img.shields.io/twitter/follow/traefik.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefik)
|
||||||
|
|
||||||
|
|
||||||
Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
||||||
Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
|
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
|
||||||
Pointing Træfik at your orchestrator should be the _only_ configuration step you need.
|
Pointing Traefik at your orchestrator should be the _only_ configuration step you need.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -43,12 +43,12 @@ Now you want users to access these microservices, and you need a reverse proxy.
|
||||||
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
|
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
|
||||||
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
|
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
|
||||||
|
|
||||||
**This is when Træfik can help you!**
|
**This is when Traefik can help you!**
|
||||||
|
|
||||||
Træfik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
|
Traefik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
|
||||||
|
|
||||||
**Run Træfik and let it do the work for you!**
|
**Run Traefik and let it do the work for you!**
|
||||||
_(But if you'd rather configure some of your routes manually, Træfik supports that too!)_
|
_(But if you'd rather configure some of your routes manually, Traefik supports that too!)_
|
||||||
|
|
||||||
![Architecture](docs/img/architecture.png)
|
![Architecture](docs/img/architecture.png)
|
||||||
|
|
||||||
|
@ -85,15 +85,15 @@ _(But if you'd rather configure some of your routes manually, Træfik supports t
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
To get your hands on Træfik, you can use the [5-Minute Quickstart](http://docs.traefik.io/#the-trfik-quickstart-using-docker) in our documentation (you will need Docker).
|
To get your hands on Traefik, you can use the [5-Minute Quickstart](http://docs.traefik.io/#the-traefik-quickstart-using-docker) in our documentation (you will need Docker).
|
||||||
|
|
||||||
Alternatively, if you don't want to install anything on your computer, you can try Træfik online in this great [Katacoda tutorial](https://www.katacoda.com/courses/traefik/deploy-load-balancer) that shows how to load balance requests between multiple Docker containers.
|
Alternatively, if you don't want to install anything on your computer, you can try Traefik online in this great [Katacoda tutorial](https://www.katacoda.com/courses/traefik/deploy-load-balancer) that shows how to load balance requests between multiple Docker containers.
|
||||||
|
|
||||||
If you are looking for a more comprehensive and real use-case example, you can also check [Play-With-Docker](http://training.play-with-docker.com/traefik-load-balancing/) to see how to load balance between multiple nodes.
|
If you are looking for a more comprehensive and real use-case example, you can also check [Play-With-Docker](http://training.play-with-docker.com/traefik-load-balancing/) to see how to load balance between multiple nodes.
|
||||||
|
|
||||||
## Web UI
|
## Web UI
|
||||||
|
|
||||||
You can access the simple HTML frontend of Træfik.
|
You can access the simple HTML frontend of Traefik.
|
||||||
|
|
||||||
![Web UI Providers](docs/img/web.frontend.png)
|
![Web UI Providers](docs/img/web.frontend.png)
|
||||||
![Web UI Health](docs/img/traefik-health.png)
|
![Web UI Health](docs/img/traefik-health.png)
|
||||||
|
@ -101,12 +101,12 @@ You can access the simple HTML frontend of Træfik.
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
|
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
|
||||||
A collection of contributions around Træfik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
To get community support, you can:
|
To get community support, you can:
|
||||||
- join the Træfik community Slack channel: [![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
|
- join the Traefik community Slack channel: [![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
|
||||||
- use [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik) (using the `traefik` tag)
|
- use [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik) (using the `traefik` tag)
|
||||||
|
|
||||||
If you need commercial support, please contact [Containo.us](https://containo.us) by mail: <mailto:support@containo.us>.
|
If you need commercial support, please contact [Containo.us](https://containo.us) by mail: <mailto:support@containo.us>.
|
||||||
|
@ -134,12 +134,12 @@ git clone https://github.com/containous/traefik
|
||||||
## Introductory Videos
|
## Introductory Videos
|
||||||
|
|
||||||
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at [GopherCon 2017](https://gophercon.com/).
|
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at [GopherCon 2017](https://gophercon.com/).
|
||||||
You will learn Træfik basics in less than 10 minutes.
|
You will learn Traefik basics in less than 10 minutes.
|
||||||
|
|
||||||
[![Traefik GopherCon 2017](https://img.youtube.com/vi/RgudiksfL-k/0.jpg)](https://www.youtube.com/watch?v=RgudiksfL-k)
|
[![Traefik GopherCon 2017](https://img.youtube.com/vi/RgudiksfL-k/0.jpg)](https://www.youtube.com/watch?v=RgudiksfL-k)
|
||||||
|
|
||||||
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
||||||
You will learn fundamental Træfik features and see some demos with Kubernetes.
|
You will learn fundamental Traefik features and see some demos with Kubernetes.
|
||||||
|
|
||||||
[![Traefik ContainerCamp UK](https://img.youtube.com/vi/aFtpIShV60I/0.jpg)](https://www.youtube.com/watch?v=aFtpIShV60I)
|
[![Traefik ContainerCamp UK](https://img.youtube.com/vi/aFtpIShV60I/0.jpg)](https://www.youtube.com/watch?v=aFtpIShV60I)
|
||||||
|
|
||||||
|
|
|
@ -451,6 +451,9 @@ func (a *ACME) buildACMEClient(account *Account) (*acme.Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acmeprovider.SetRecursiveNameServers(a.DNSChallenge.Resolvers)
|
||||||
|
acmeprovider.SetPropagationCheck(a.DNSChallenge.DisablePropagationCheck)
|
||||||
|
|
||||||
var provider acme.ChallengeProvider
|
var provider acme.ChallengeProvider
|
||||||
provider, err = dns.NewDNSChallengeProviderByName(a.DNSChallenge.Provider)
|
provider, err = dns.NewDNSChallengeProviderByName(a.DNSChallenge.Provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -64,6 +64,14 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $service.TraefikLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."backend-{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $service.TraefikLabels }}
|
{{ $loadBalancer := getLoadBalancer $service.TraefikLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."backend-{{ $backendName }}".loadBalancer]
|
[backends."backend-{{ $backendName }}".loadBalancer]
|
||||||
|
@ -338,6 +346,12 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $backend.SegmentLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."backend-{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $backend.SegmentLabels }}
|
{{ $loadBalancer := getLoadBalancer $backend.SegmentLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."backend-{{ $backendName }}".loadBalancer]
|
[backends."backend-{{ $backendName }}".loadBalancer]
|
||||||
|
@ -613,6 +627,12 @@ var _templatesEcsTmpl = []byte(`[backends]
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $firstInstance.SegmentLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."backend-{{ $serviceName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $firstInstance.SegmentLabels }}
|
{{ $loadBalancer := getLoadBalancer $firstInstance.SegmentLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."backend-{{ $serviceName }}".loadBalancer]
|
[backends."backend-{{ $serviceName }}".loadBalancer]
|
||||||
|
@ -929,6 +949,11 @@ var _templatesKubernetesTmpl = []byte(`[backends]
|
||||||
expression = "{{ $backend.CircuitBreaker.Expression }}"
|
expression = "{{ $backend.CircuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if $backend.ResponseForwarding }}
|
||||||
|
[backends."{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $backend.responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
[backends."{{ $backendName }}".loadBalancer]
|
[backends."{{ $backendName }}".loadBalancer]
|
||||||
method = "{{ $backend.LoadBalancer.Method }}"
|
method = "{{ $backend.LoadBalancer.Method }}"
|
||||||
{{if $backend.LoadBalancer.Stickiness }}
|
{{if $backend.LoadBalancer.Stickiness }}
|
||||||
|
@ -1055,6 +1080,28 @@ var _templatesKubernetesTmpl = []byte(`[backends]
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if $frontend.PassTLSClientCert }}
|
||||||
|
[frontends."{{ $frontendName }}".passTLSClientCert]
|
||||||
|
pem = {{ $frontend.PassTLSClientCert.PEM }}
|
||||||
|
{{ $infos := $frontend.PassTLSClientCert.Infos }}
|
||||||
|
{{if $infos }}
|
||||||
|
[frontends."{{ $frontendName }}".passTLSClientCert.infos]
|
||||||
|
notAfter = {{ $infos.NotAfter }}
|
||||||
|
notBefore = {{ $infos.NotBefore }}
|
||||||
|
sans = {{ $infos.Sans }}
|
||||||
|
{{ $subject := $infos.Subject }}
|
||||||
|
{{if $subject }}
|
||||||
|
[frontends."{{ $frontendName }}".passTLSClientCert.infos.subject]
|
||||||
|
country = {{ $subject.Country }}
|
||||||
|
province = {{ $subject.Province }}
|
||||||
|
locality = {{ $subject.Locality }}
|
||||||
|
organization = {{ $subject.Organization }}
|
||||||
|
commonName = {{ $subject.CommonName }}
|
||||||
|
serialNumber = {{ $subject.SerialNumber }}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if $frontend.Headers }}
|
{{if $frontend.Headers }}
|
||||||
[frontends."{{ $frontendName }}".headers]
|
[frontends."{{ $frontendName }}".headers]
|
||||||
SSLRedirect = {{ $frontend.Headers.SSLRedirect }}
|
SSLRedirect = {{ $frontend.Headers.SSLRedirect }}
|
||||||
|
@ -1147,6 +1194,12 @@ var _templatesKvTmpl = []byte(`[backends]
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $backend }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.flushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $backend }}
|
{{ $loadBalancer := getLoadBalancer $backend }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."{{ $backendName }}".loadBalancer]
|
[backends."{{ $backendName }}".loadBalancer]
|
||||||
|
@ -1438,6 +1491,12 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $app.SegmentLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $app.SegmentLabels }}
|
{{ $loadBalancer := getLoadBalancer $app.SegmentLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."{{ $backendName }}".loadBalancer]
|
[backends."{{ $backendName }}".loadBalancer]
|
||||||
|
@ -1714,6 +1773,12 @@ var _templatesMesosTmpl = []byte(`[backends]
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $app.TraefikLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."backend-{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $app.TraefikLabels }}
|
{{ $loadBalancer := getLoadBalancer $app.TraefikLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."backend-{{ $backendName }}".loadBalancer]
|
[backends."backend-{{ $backendName }}".loadBalancer]
|
||||||
|
@ -2013,6 +2078,12 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
|
||||||
expression = "{{ $circuitBreaker.Expression }}"
|
expression = "{{ $circuitBreaker.Expression }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $responseForwarding := getResponseForwarding $backend.SegmentLabels }}
|
||||||
|
{{if $responseForwarding }}
|
||||||
|
[backends."backend-{{ $backendName }}".responseForwarding]
|
||||||
|
flushInterval = "{{ $responseForwarding.FlushInterval }}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{ $loadBalancer := getLoadBalancer $backend.SegmentLabels }}
|
{{ $loadBalancer := getLoadBalancer $backend.SegmentLabels }}
|
||||||
{{if $loadBalancer }}
|
{{if $loadBalancer }}
|
||||||
[backends."backend-{{ $backendName }}".loadBalancer]
|
[backends."backend-{{ $backendName }}".loadBalancer]
|
||||||
|
|
|
@ -71,6 +71,7 @@ Complete documentation is available at https://traefik.io`,
|
||||||
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
||||||
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
||||||
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
||||||
|
f.AddParser(reflect.TypeOf(types.DNSResolvers{}), &types.DNSResolvers{})
|
||||||
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
|
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
|
||||||
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
|
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
|
||||||
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
|
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
|
||||||
|
|
|
@ -85,6 +85,7 @@ type GlobalConfiguration struct {
|
||||||
HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
|
HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
|
||||||
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
|
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
|
||||||
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
|
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
|
||||||
|
KeepTrailingSlash bool `description:"Do not remove trailing slash." export:"true"` // Deprecated
|
||||||
Docker *docker.Provider `description:"Enable Docker backend with default settings" export:"true"`
|
Docker *docker.Provider `description:"Enable Docker backend with default settings" export:"true"`
|
||||||
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
|
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
|
||||||
Marathon *marathon.Provider `description:"Enable Marathon backend with default settings" export:"true"`
|
Marathon *marathon.Provider `description:"Enable Marathon backend with default settings" export:"true"`
|
||||||
|
|
|
@ -14,12 +14,12 @@ Let's take our example from the [overview](/#overview) again:
|
||||||
|
|
||||||
> ![Architecture](img/architecture.png)
|
> ![Architecture](img/architecture.png)
|
||||||
|
|
||||||
Let's zoom on Træfik and have an overview of its internal architecture:
|
Let's zoom on Traefik and have an overview of its internal architecture:
|
||||||
|
|
||||||
|
|
||||||
![Architecture](img/internal.png)
|
![Architecture](img/internal.png)
|
||||||
|
|
||||||
- Incoming requests end on [entrypoints](#entrypoints), as the name suggests, they are the network entry points into Træfik (listening port, SSL, traffic redirection...).
|
- Incoming requests end on [entrypoints](#entrypoints), as the name suggests, they are the network entry points into Traefik (listening port, SSL, traffic redirection...).
|
||||||
- Traffic is then forwarded to a matching [frontend](#frontends). A frontend defines routes from [entrypoints](#entrypoints) to [backends](#backends).
|
- Traffic is then forwarded to a matching [frontend](#frontends). A frontend defines routes from [entrypoints](#entrypoints) to [backends](#backends).
|
||||||
Routes are created using requests fields (`Host`, `Path`, `Headers`...) and can match or not a request.
|
Routes are created using requests fields (`Host`, `Path`, `Headers`...) and can match or not a request.
|
||||||
- The [frontend](#frontends) will then send the request to a [backend](#backends). A backend can be composed by one or more [servers](#servers), and by a load-balancing strategy.
|
- The [frontend](#frontends) will then send the request to a [backend](#backends). A backend can be composed by one or more [servers](#servers), and by a load-balancing strategy.
|
||||||
|
@ -27,7 +27,7 @@ Routes are created using requests fields (`Host`, `Path`, `Headers`...) and can
|
||||||
|
|
||||||
### Entrypoints
|
### Entrypoints
|
||||||
|
|
||||||
Entrypoints are the network entry points into Træfik.
|
Entrypoints are the network entry points into Traefik.
|
||||||
They can be defined using:
|
They can be defined using:
|
||||||
|
|
||||||
- a port (80, 443...)
|
- a port (80, 443...)
|
||||||
|
@ -511,16 +511,16 @@ Additional http headers and hostname to health check request can be specified, f
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Træfik's configuration has two parts:
|
Traefik's configuration has two parts:
|
||||||
|
|
||||||
- The [static Træfik configuration](/basics#static-trfik-configuration) which is loaded only at the beginning.
|
- The [static Traefik configuration](/basics#static-traefik-configuration) which is loaded only at the beginning.
|
||||||
- The [dynamic Træfik configuration](/basics#dynamic-trfik-configuration) which can be hot-reloaded (no need to restart the process).
|
- The [dynamic Traefik configuration](/basics#dynamic-traefik-configuration) which can be hot-reloaded (no need to restart the process).
|
||||||
|
|
||||||
### Static Træfik configuration
|
### Static Traefik configuration
|
||||||
|
|
||||||
The static configuration is the global configuration which is setting up connections to configuration backends and entrypoints.
|
The static configuration is the global configuration which is setting up connections to configuration backends and entrypoints.
|
||||||
|
|
||||||
Træfik can be configured using many configuration sources with the following precedence order.
|
Traefik can be configured using many configuration sources with the following precedence order.
|
||||||
Each item takes precedence over the item below it:
|
Each item takes precedence over the item below it:
|
||||||
|
|
||||||
- [Key-value store](/basics/#key-value-stores)
|
- [Key-value store](/basics/#key-value-stores)
|
||||||
|
@ -536,7 +536,7 @@ It means that arguments override configuration file, and key-value store overrid
|
||||||
|
|
||||||
#### Configuration file
|
#### Configuration file
|
||||||
|
|
||||||
By default, Træfik will try to find a `traefik.toml` in the following places:
|
By default, Traefik will try to find a `traefik.toml` in the following places:
|
||||||
|
|
||||||
- `/etc/traefik/`
|
- `/etc/traefik/`
|
||||||
- `$HOME/.traefik/`
|
- `$HOME/.traefik/`
|
||||||
|
@ -562,7 +562,7 @@ Note that all default values will be displayed as well.
|
||||||
|
|
||||||
#### Key-value stores
|
#### Key-value stores
|
||||||
|
|
||||||
Træfik supports several Key-value stores:
|
Traefik supports several Key-value stores:
|
||||||
|
|
||||||
- [Consul](https://consul.io)
|
- [Consul](https://consul.io)
|
||||||
- [etcd](https://coreos.com/etcd/)
|
- [etcd](https://coreos.com/etcd/)
|
||||||
|
@ -571,7 +571,7 @@ Træfik supports several Key-value stores:
|
||||||
|
|
||||||
Please refer to the [User Guide Key-value store configuration](/user-guide/kv-config/) section to get documentation on it.
|
Please refer to the [User Guide Key-value store configuration](/user-guide/kv-config/) section to get documentation on it.
|
||||||
|
|
||||||
### Dynamic Træfik configuration
|
### Dynamic Traefik configuration
|
||||||
|
|
||||||
The dynamic configuration concerns :
|
The dynamic configuration concerns :
|
||||||
|
|
||||||
|
@ -580,9 +580,9 @@ The dynamic configuration concerns :
|
||||||
- [Servers](/basics/#servers)
|
- [Servers](/basics/#servers)
|
||||||
- HTTPS Certificates
|
- HTTPS Certificates
|
||||||
|
|
||||||
Træfik can hot-reload those rules which could be provided by [multiple configuration backends](/configuration/commons).
|
Traefik can hot-reload those rules which could be provided by [multiple configuration backends](/configuration/commons).
|
||||||
|
|
||||||
We only need to enable `watch` option to make Træfik watch configuration backend changes and generate its configuration automatically.
|
We only need to enable `watch` option to make Traefik watch configuration backend changes and generate its configuration automatically.
|
||||||
Routes to services will be created and updated instantly at any changes.
|
Routes to services will be created and updated instantly at any changes.
|
||||||
|
|
||||||
Please refer to the [configuration backends](/configuration/commons) section to get documentation on it.
|
Please refer to the [configuration backends](/configuration/commons) section to get documentation on it.
|
||||||
|
@ -596,10 +596,10 @@ Usage:
|
||||||
traefik [command] [--flag=flag_argument]
|
traefik [command] [--flag=flag_argument]
|
||||||
```
|
```
|
||||||
|
|
||||||
List of Træfik available commands with description :
|
List of Traefik available commands with description :
|
||||||
|
|
||||||
- `version` : Print version
|
- `version` : Print version
|
||||||
- `storeconfig` : Store the static Traefik configuration into a Key-value stores. Please refer to the [Store Træfik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
|
- `storeconfig` : Store the static Traefik configuration into a Key-value stores. Please refer to the [Store Traefik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
|
||||||
- `bug`: The easiest way to submit a pre-filled issue.
|
- `bug`: The easiest way to submit a pre-filled issue.
|
||||||
- `healthcheck`: Calls Traefik `/ping` to check health.
|
- `healthcheck`: Calls Traefik `/ping` to check health.
|
||||||
|
|
||||||
|
@ -624,7 +624,7 @@ docker run traefik[:version] --help
|
||||||
|
|
||||||
### Command: bug
|
### Command: bug
|
||||||
|
|
||||||
Here is the easiest way to submit a pre-filled issue on [Træfik GitHub](https://github.com/containous/traefik).
|
Here is the easiest way to submit a pre-filled issue on [Traefik GitHub](https://github.com/containous/traefik).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
traefik bug
|
traefik bug
|
||||||
|
@ -657,14 +657,14 @@ You can read the public proposal on this topic [here](https://github.com/contain
|
||||||
|
|
||||||
### Why ?
|
### Why ?
|
||||||
|
|
||||||
In order to help us learn more about how Træfik is being used and improve it, we collect anonymous usage statistics from running instances.
|
In order to help us learn more about how Traefik is being used and improve it, we collect anonymous usage statistics from running instances.
|
||||||
Those data help us prioritize our developments and focus on what's more important (for example, which configuration backend is used and which is not used).
|
Those data help us prioritize our developments and focus on what's more important (for example, which configuration backend is used and which is not used).
|
||||||
|
|
||||||
### What ?
|
### What ?
|
||||||
|
|
||||||
Once a day (the first call begins 10 minutes after the start of Træfik), we collect:
|
Once a day (the first call begins 10 minutes after the start of Traefik), we collect:
|
||||||
|
|
||||||
- the Træfik version
|
- the Traefik version
|
||||||
- a hash of the configuration
|
- a hash of the configuration
|
||||||
- an **anonymous version** of the static configuration:
|
- an **anonymous version** of the static configuration:
|
||||||
- token, user name, password, URL, IP, domain, email, etc, are removed
|
- token, user name, password, URL, IP, domain, email, etc, are removed
|
||||||
|
|
|
@ -15,7 +15,7 @@ I used 4 VMs for the tests with the following configuration:
|
||||||
|
|
||||||
1. One VM used to launch the benchmarking tool [wrk](https://github.com/wg/wrk)
|
1. One VM used to launch the benchmarking tool [wrk](https://github.com/wg/wrk)
|
||||||
2. One VM for Traefik (v1.0.0-beta.416) / nginx (v1.4.6)
|
2. One VM for Traefik (v1.0.0-beta.416) / nginx (v1.4.6)
|
||||||
3. Two VMs for 2 backend servers in go [whoami](https://github.com/emilevauge/whoamI/)
|
3. Two VMs for 2 backend servers in go [whoami](https://github.com/containous/whoami/)
|
||||||
|
|
||||||
Each VM has been tuned using the following limits:
|
Each VM has been tuned using the following limits:
|
||||||
|
|
||||||
|
|
|
@ -142,8 +142,26 @@ entryPoint = "https"
|
||||||
#
|
#
|
||||||
# delayBeforeCheck = 0
|
# delayBeforeCheck = 0
|
||||||
|
|
||||||
|
# Use following DNS servers to resolve the FQDN authority.
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: empty
|
||||||
|
#
|
||||||
|
# resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||||
|
|
||||||
|
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
|
||||||
|
#
|
||||||
|
# NOT RECOMMENDED:
|
||||||
|
# Increase the risk of reaching Let's Encrypt's rate limits.
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: false
|
||||||
|
#
|
||||||
|
# disablePropagationCheck = true
|
||||||
|
|
||||||
# Domains list.
|
# Domains list.
|
||||||
# Only domains defined here can generate wildcard certificates.
|
# Only domains defined here can generate wildcard certificates.
|
||||||
|
# The certificates for these domains are negotiated at traefik startup only.
|
||||||
#
|
#
|
||||||
# [[acme.domains]]
|
# [[acme.domains]]
|
||||||
# main = "local1.com"
|
# main = "local1.com"
|
||||||
|
@ -181,6 +199,10 @@ entryPoint = "https"
|
||||||
[acme.tlsChallenge]
|
[acme.tlsChallenge]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
If the `TLS-ALPN-01` challenge is used, `acme.entryPoint` has to be reachable by Let's Encrypt through port 443.
|
||||||
|
This is a Let's Encrypt limitation as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
|
||||||
|
|
||||||
#### `httpChallenge`
|
#### `httpChallenge`
|
||||||
|
|
||||||
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning a HTTP resource under a well-known URI.
|
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning a HTTP resource under a well-known URI.
|
||||||
|
@ -251,57 +273,65 @@ Useful if internal networks block external DNS queries.
|
||||||
|
|
||||||
Here is a list of supported `provider`s, that can automate the DNS verification, along with the required environment variables and their [wildcard & root domain support](/configuration/acme/#wildcard-domains) for each. Do not hesitate to complete it.
|
Here is a list of supported `provider`s, that can automate the DNS verification, along with the required environment variables and their [wildcard & root domain support](/configuration/acme/#wildcard-domains) for each. Do not hesitate to complete it.
|
||||||
|
|
||||||
| Provider Name | Provider Code | Environment Variables | Wildcard & Root Domain Support |
|
| Provider Name | Provider Code | Environment Variables | Wildcard & Root Domain Support |
|
||||||
|--------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------|--------------------------------|
|
|--------------------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|
|
||||||
| [Alibaba Cloud](https://www.vultr.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | Not tested yet |
|
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acmedns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | Not tested yet |
|
||||||
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | Not tested yet |
|
| [Alibaba Cloud](https://www.vultr.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | Not tested yet |
|
||||||
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP` | Not tested yet |
|
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | Not tested yet |
|
||||||
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | Not tested yet |
|
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | Not tested yet |
|
||||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` - The `Global API Key` needs to be used, not the `Origin CA Key` | YES |
|
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | Not tested yet |
|
||||||
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | Not tested yet |
|
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` - The `Global API Key` needs to be used, not the `Origin CA Key` | YES |
|
||||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | YES |
|
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | Not tested yet |
|
||||||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | Not tested yet |
|
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | YES |
|
||||||
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | Not tested yet |
|
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | Not tested yet |
|
||||||
| [DNSPod](http://www.dnspod.net/) | `dnspod` | `DNSPOD_API_KEY` | Not tested yet |
|
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | Not tested yet |
|
||||||
| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | YES |
|
| [DNSPod](http://www.dnspod.net/) | `dnspod` | `DNSPOD_API_KEY` | Not tested yet |
|
||||||
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | Not tested yet |
|
| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | YES |
|
||||||
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | Not tested yet |
|
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | No |
|
||||||
| External Program | `exec` | `EXEC_PATH` | Not tested yet |
|
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | Not tested yet |
|
||||||
| [Exoscale](https://www.exoscale.ch) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | YES |
|
| External Program | `exec` | `EXEC_PATH` | Not tested yet |
|
||||||
| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | Not tested yet |
|
| [Exoscale](https://www.exoscale.com) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | YES |
|
||||||
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | Not tested yet |
|
| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | Not tested yet |
|
||||||
| [Gandi v5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | YES |
|
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | Not tested yet |
|
||||||
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | Not tested yet |
|
| [Gandi v5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | YES |
|
||||||
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | Not tested yet |
|
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | Not tested yet |
|
||||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` | YES |
|
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | Not tested yet |
|
||||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | Not tested yet |
|
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` | YES |
|
||||||
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | Not tested yet |
|
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | Not tested yet |
|
||||||
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | Not tested yet |
|
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | Not tested yet |
|
||||||
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | Not tested yet |
|
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | Not tested yet |
|
||||||
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | Not tested yet |
|
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | Not tested yet |
|
||||||
| manual | - | none, but you need to run Træfik interactively, turn on `acmeLogging` to see instructions and press <kbd>Enter</kbd>. | YES |
|
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | Not tested yet |
|
||||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | YES |
|
| manual | - | none, but you need to run Traefik interactively, turn on `acmeLogging` to see instructions and press <kbd>Enter</kbd>. | YES |
|
||||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | Not tested yet |
|
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | YES |
|
||||||
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | Not tested yet |
|
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | Not tested yet |
|
||||||
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | Not tested yet |
|
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | Not tested yet |
|
||||||
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | Not tested yet |
|
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | Not tested yet |
|
||||||
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | Not tested yet |
|
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | Not tested yet |
|
||||||
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | YES |
|
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | Not tested yet |
|
||||||
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | Not tested yet |
|
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | YES |
|
||||||
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | Not tested yet |
|
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | Not tested yet |
|
||||||
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | Not tested yet |
|
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | Not tested yet |
|
||||||
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | YES |
|
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | Not tested yet |
|
||||||
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | Not tested yet |
|
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | YES |
|
||||||
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | Not tested yet |
|
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | Not tested yet |
|
||||||
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | Not tested yet |
|
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | Not tested yet |
|
||||||
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | Not tested yet |
|
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | Not tested yet |
|
||||||
|
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | Not tested yet |
|
||||||
|
|
||||||
|
#### `resolvers`
|
||||||
|
|
||||||
|
Use custom DNS servers to resolve the FQDN authority.
|
||||||
|
|
||||||
### `domains`
|
### `domains`
|
||||||
|
|
||||||
You can provide SANs (alternative domains) to each main domain.
|
You can provide SANs (alternative domains) to each main domain.
|
||||||
All domains must have A/AAAA records pointing to Træfik.
|
All domains must have A/AAAA records pointing to Traefik.
|
||||||
Each domain & SAN will lead to a certificate request.
|
Each domain & SAN will lead to a certificate request.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
The certificates for the domains listed in `acme.domains` are negotiated at traefik startup only.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
|
@ -340,8 +370,8 @@ It is not possible to request a double wildcard certificate for a domain (for ex
|
||||||
Due to ACME limitation it is not possible to define wildcards in SANs (alternative domains). Thus, the wildcard domain has to be defined as a main domain.
|
Due to ACME limitation it is not possible to define wildcards in SANs (alternative domains). Thus, the wildcard domain has to be defined as a main domain.
|
||||||
Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 `DNS-01` challenges are executed.
|
Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 `DNS-01` challenges are executed.
|
||||||
In this case the generated DNS TXT record for both domains is the same.
|
In this case the generated DNS TXT record for both domains is the same.
|
||||||
Eventhough this behavior is [DNS RFC](https://community.letsencrypt.org/t/wildcard-issuance-two-txt-records-for-the-same-name/54528/2) compliant, it can lead to problems as all DNS providers keep DNS records cached for a certain time (TTL) and this TTL can be superior to the challenge timeout making the `DNS-01` challenge fail.
|
Even though this behavior is [DNS RFC](https://community.letsencrypt.org/t/wildcard-issuance-two-txt-records-for-the-same-name/54528/2) compliant, it can lead to problems as all DNS providers keep DNS records cached for a certain time (TTL) and this TTL can be superior to the challenge timeout making the `DNS-01` challenge fail.
|
||||||
The Træfik ACME client library [LEGO](https://github.com/xenolf/lego) supports some but not all DNS providers to work around this issue.
|
The Traefik ACME client library [LEGO](https://github.com/xenolf/lego) supports some but not all DNS providers to work around this issue.
|
||||||
The [`provider` table](/configuration/acme/#provider) indicates if they allow generating certificates for a wildcard domain and its root domain.
|
The [`provider` table](/configuration/acme/#provider) indicates if they allow generating certificates for a wildcard domain and its root domain.
|
||||||
|
|
||||||
### `onDemand` (Deprecated)
|
### `onDemand` (Deprecated)
|
||||||
|
@ -421,7 +451,7 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
This file cannot be shared across multiple instances of Træfik at the same time. Please use a [KV Store entry](/configuration/acme/#as-a-key-value-store-entry) instead.
|
This file cannot be shared across multiple instances of Traefik at the same time. Please use a [KV Store entry](/configuration/acme/#as-a-key-value-store-entry) instead.
|
||||||
|
|
||||||
#### As a Key Value Store Entry
|
#### As a Key Value Store Entry
|
||||||
|
|
||||||
|
@ -443,8 +473,8 @@ During migration from ACME v1 to ACME v2, using a storage file, a backup of the
|
||||||
For example: if `acme.storage`'s value is `/etc/traefik/acme/acme.json`, the backup file will be `/etc/traefik/acme/acme.json.bak`.
|
For example: if `acme.storage`'s value is `/etc/traefik/acme/acme.json`, the backup file will be `/etc/traefik/acme/acme.json.bak`.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
When Træfik is launched in a container, the storage file's parent directory needs to be mounted to be able to access the backup file on the host.
|
When Traefik is launched in a container, the storage file's parent directory needs to be mounted to be able to access the backup file on the host.
|
||||||
Otherwise the backup file will be deleted when the container is stopped. Træfik will only generate it once!
|
Otherwise the backup file will be deleted when the container is stopped. Traefik will only generate it once!
|
||||||
|
|
||||||
### `dnsProvider` (Deprecated)
|
### `dnsProvider` (Deprecated)
|
||||||
|
|
||||||
|
@ -465,4 +495,4 @@ If Let's Encrypt is not reachable, these certificates will be used:
|
||||||
1. Provided certificates
|
1. Provided certificates
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
For new (sub)domains which need Let's Encrypt authentification, the default Træfik certificate will be used until Træfik is restarted.
|
For new (sub)domains which need Let's Encrypt authentification, the default Traefik certificate will be used until Traefik is restarted.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# API definition
|
# API definition
|
||||||
# Warning: Enabling API will expose Træfik's configuration.
|
# Warning: Enabling API will expose Traefik's configuration.
|
||||||
# It is not recommended in production,
|
# It is not recommended in production,
|
||||||
# unless secured by authentication and authorizations
|
# unless secured by authentication and authorizations
|
||||||
[api]
|
[api]
|
||||||
|
@ -61,7 +61,7 @@ keeping it restricted over internal networks
|
||||||
|
|
||||||
| Path | Method | Description |
|
| Path | Method | Description |
|
||||||
|-----------------------------------------------------------------|------------------|-------------------------------------------|
|
|-----------------------------------------------------------------|------------------|-------------------------------------------|
|
||||||
| `/` | `GET` | Provides a simple HTML frontend of Træfik |
|
| `/` | `GET` | Provides a simple HTML frontend of Traefik |
|
||||||
| `/cluster/leader` | `GET` | JSON leader true/false response |
|
| `/cluster/leader` | `GET` | JSON leader true/false response |
|
||||||
| `/health` | `GET` | JSON health metrics |
|
| `/health` | `GET` | JSON health metrics |
|
||||||
| `/api` | `GET` | Configuration for all providers |
|
| `/api` | `GET` | Configuration for all providers |
|
||||||
|
@ -268,11 +268,11 @@ curl -s "http://localhost:8080/health" | jq .
|
||||||
```
|
```
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
// Træfik PID
|
// Traefik PID
|
||||||
"pid": 2458,
|
"pid": 2458,
|
||||||
// Træfik server uptime (formated time)
|
// Traefik server uptime (formated time)
|
||||||
"uptime": "39m6.885931127s",
|
"uptime": "39m6.885931127s",
|
||||||
// Træfik server uptime in seconds
|
// Traefik server uptime in seconds
|
||||||
"uptime_sec": 2346.885931127,
|
"uptime_sec": 2346.885931127,
|
||||||
// current server date
|
// current server date
|
||||||
"time": "2015-10-07 18:32:24.362238909 +0200 CEST",
|
"time": "2015-10-07 18:32:24.362238909 +0200 CEST",
|
||||||
|
@ -282,7 +282,7 @@ curl -s "http://localhost:8080/health" | jq .
|
||||||
"status_code_count": {
|
"status_code_count": {
|
||||||
"502": 1
|
"502": 1
|
||||||
},
|
},
|
||||||
// count HTTP response status code since Træfik started
|
// count HTTP response status code since Traefik started
|
||||||
"total_status_code_count": {
|
"total_status_code_count": {
|
||||||
"200": 7,
|
"200": 7,
|
||||||
"404": 21,
|
"404": 21,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# BoltDB Provider
|
# BoltDB Provider
|
||||||
|
|
||||||
Træfik can be configured to use BoltDB as a provider.
|
Traefik can be configured to use BoltDB as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Consul Key-Value Provider
|
# Consul Key-Value Provider
|
||||||
|
|
||||||
Træfik can be configured to use Consul as a provider.
|
Traefik can be configured to use Consul as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Consul Catalog Provider
|
# Consul Catalog Provider
|
||||||
|
|
||||||
Træfik can be configured to use service discovery catalog of Consul as a provider.
|
Traefik can be configured to use service discovery catalog of Consul as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
@ -96,7 +96,7 @@ Additional settings can be defined using Consul Catalog tags.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `<prefix>.enable=false` | Disables this container in Træfik. |
|
| `<prefix>.enable=false` | Disables this container in Traefik. |
|
||||||
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
|
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
|
||||||
| `<prefix>.weight=10` | Assigns this weight to the container. |
|
| `<prefix>.weight=10` | Assigns this weight to the container. |
|
||||||
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
|
@ -105,6 +105,7 @@ Additional settings can be defined using Consul Catalog tags.
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
|
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
|
||||||
|
| `<prefix>.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `<prefix>.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
| `<prefix>.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
||||||
| `<prefix>.backend.healthcheck.timeout=3s` | Defines the health check request timeout |
|
| `<prefix>.backend.healthcheck.timeout=3s` | Defines the health check request timeout |
|
||||||
|
@ -202,7 +203,7 @@ If you need to support multiple frontends for a service, for example when having
|
||||||
| `<prefix>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `<prefix>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `<prefix>.frontend.headers.hostsProxyHeaders=EXPR` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `<prefix>.frontend.headers.hostsProxyHeaders=EXPR` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `<prefix>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `<prefix>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `<prefix>.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `<prefix>.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `<prefix>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `<prefix>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `<prefix>.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `<prefix>.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `<prefix>.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `<prefix>.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
@ -216,7 +217,7 @@ If you need to support multiple frontends for a service, for example when having
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
If you want that Træfik uses Consul tags correctly you need to defined them like that:
|
If you want that Traefik uses Consul tags correctly you need to defined them like that:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
traefik.enable=true
|
traefik.enable=true
|
||||||
|
@ -224,7 +225,7 @@ traefik.tags=api
|
||||||
traefik.tags=external
|
traefik.tags=external
|
||||||
```
|
```
|
||||||
|
|
||||||
If the prefix defined in Træfik configuration is `bla`, tags need to be defined like that:
|
If the prefix defined in Traefik configuration is `bla`, tags need to be defined like that:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
bla.enable=true
|
bla.enable=true
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# Docker Provider
|
# Docker Provider
|
||||||
|
|
||||||
Træfik can be configured to use Docker as a provider.
|
Traefik can be configured to use Docker as a provider.
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ endpoint = "unix:///var/run/docker.sock"
|
||||||
# Default base domain used for the frontend rules.
|
# Default base domain used for the frontend rules.
|
||||||
# Can be overridden by setting the "traefik.domain" label on a container.
|
# Can be overridden by setting the "traefik.domain" label on a container.
|
||||||
#
|
#
|
||||||
# Required
|
# Optional
|
||||||
#
|
#
|
||||||
domain = "docker.localhost"
|
domain = "docker.localhost"
|
||||||
|
|
||||||
|
@ -213,9 +213,9 @@ Labels can be used on containers to override default behavior.
|
||||||
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] |
|
| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] |
|
||||||
| `traefik.domain` | Sets the default base domain for the frontend rules. For more information, check the [Container Labels section's of the user guide "Let's Encrypt & Docker"](/user-guide/docker-and-lets-encrypt/#container-labels) |
|
| `traefik.domain` | Sets the default base domain for the frontend rules. For more information, check the [Container Labels section's of the user guide "Let's Encrypt & Docker"](/user-guide/docker-and-lets-encrypt/#container-labels) |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Traefik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
||||||
| `traefik.tags=foo,bar,myTag` | Adds Træfik tags to the Docker container/service to be used in [constraints](/configuration/commons/#constraints). |
|
| `traefik.tags=foo,bar,myTag` | Adds Traefik tags to the Docker container/service to be used in [constraints](/configuration/commons/#constraints). |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container |
|
| `traefik.weight=10` | Assigns this weight to the container |
|
||||||
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
|
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
|
||||||
|
@ -225,6 +225,7 @@ Labels can be used on containers to override default behavior.
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
||||||
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. |
|
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. |
|
||||||
|
@ -317,7 +318,7 @@ The result will be `user:$$apr1$$9Cv/OMGj$$ZomWQzuQbL.3TRCS81A1g/`, note additio
|
||||||
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
@ -430,16 +431,16 @@ Segment labels override the default behavior.
|
||||||
More details in this [example](/user-guide/docker-and-lets-encrypt/#labels).
|
More details in this [example](/user-guide/docker-and-lets-encrypt/#labels).
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
When running inside a container, Træfik will need network access through:
|
When running inside a container, Traefik will need network access through:
|
||||||
|
|
||||||
`docker network connect <network> <traefik-container>`
|
`docker network connect <network> <traefik-container>`
|
||||||
|
|
||||||
## usebindportip
|
## usebindportip
|
||||||
|
|
||||||
The default behavior of Træfik is to route requests to the IP/Port of the matching container.
|
The default behavior of Traefik is to route requests to the IP/Port of the matching container.
|
||||||
When setting `usebindportip` to true, you tell Træfik to use the IP/Port attached to the container's binding instead of the inner network IP/Port.
|
When setting `usebindportip` to true, you tell Traefik to use the IP/Port attached to the container's binding instead of the inner network IP/Port.
|
||||||
|
|
||||||
When used in conjunction with the `traefik.port` label (that tells Træfik to route requests to a specific port), Træfik tries to find a binding with `traefik.port` port to select the container. If it can't find such a binding, Træfik falls back on the internal network IP of the container, but still uses the `traefik.port` that is set in the label.
|
When used in conjunction with the `traefik.port` label (that tells Traefik to route requests to a specific port), Traefik tries to find a binding with `traefik.port` port to select the container. If it can't find such a binding, Traefik falls back on the internal network IP of the container, but still uses the `traefik.port` that is set in the label.
|
||||||
|
|
||||||
Below is a recap of the behavior of `usebindportip` in different situations.
|
Below is a recap of the behavior of `usebindportip` in different situations.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# DynamoDB Provider
|
# DynamoDB Provider
|
||||||
|
|
||||||
Træfik can be configured to use Amazon DynamoDB as a provider.
|
Traefik can be configured to use Amazon DynamoDB as a provider.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# ECS Provider
|
# ECS Provider
|
||||||
|
|
||||||
Træfik can be configured to use Amazon ECS as a provider.
|
Traefik can be configured to use Amazon ECS as a provider.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ To enable constraints see [provider-specific constraints section](/configuration
|
||||||
|
|
||||||
## Policy
|
## Policy
|
||||||
|
|
||||||
Træfik needs the following policy to read ECS information:
|
Traefik needs the following policy to read ECS information:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -132,8 +132,8 @@ Labels can be used on task containers to override default behavior:
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain for frontend rules. |
|
| `traefik.domain` | Sets the default base domain for frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Traefik. |
|
||||||
| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container |
|
| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container |
|
| `traefik.weight=10` | Assigns this weight to the container |
|
||||||
|
@ -144,6 +144,7 @@ Labels can be used on task containers to override default behavior:
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
||||||
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
||||||
|
@ -224,7 +225,7 @@ Labels can be used on task containers to override default behavior:
|
||||||
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
|
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
|
||||||
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Etcd Provider
|
# Etcd Provider
|
||||||
|
|
||||||
Træfik can be configured to use Etcd as a provider.
|
Traefik can be configured to use Etcd as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Eureka Provider
|
# Eureka Provider
|
||||||
|
|
||||||
Træfik can be configured to use Eureka as a provider.
|
Traefik can be configured to use Eureka as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# File Provider
|
# File Provider
|
||||||
|
|
||||||
Træfik can be configured with a file.
|
Traefik can be configured with a file.
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ Træfik can be configured with a file.
|
||||||
[backends.backend1.circuitBreaker]
|
[backends.backend1.circuitBreaker]
|
||||||
expression = "NetworkErrorRatio() > 0.5"
|
expression = "NetworkErrorRatio() > 0.5"
|
||||||
|
|
||||||
|
[backends.backend1.responseForwarding]
|
||||||
|
flushInterval = "10ms"
|
||||||
|
|
||||||
[backends.backend1.loadBalancer]
|
[backends.backend1.loadBalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[backends.backend1.loadBalancer.stickiness]
|
[backends.backend1.loadBalancer.stickiness]
|
||||||
|
@ -190,16 +193,16 @@ Træfik can be configured with a file.
|
||||||
|
|
||||||
You have two choices:
|
You have two choices:
|
||||||
|
|
||||||
- [Rules in Træfik configuration file](/configuration/backends/file/#rules-in-trfik-configuration-file)
|
- [Rules in Traefik configuration file](/configuration/backends/file/#rules-in-traefik-configuration-file)
|
||||||
- [Rules in dedicated files](/configuration/backends/file/#rules-in-dedicated-files)
|
- [Rules in dedicated files](/configuration/backends/file/#rules-in-dedicated-files)
|
||||||
|
|
||||||
To enable the file backend, you must either pass the `--file` option to the Træfik binary or put the `[file]` section (with or without inner settings) in the configuration file.
|
To enable the file backend, you must either pass the `--file` option to the Traefik binary or put the `[file]` section (with or without inner settings) in the configuration file.
|
||||||
|
|
||||||
The configuration file allows managing both backends/frontends and HTTPS certificates (which are not [Let's Encrypt](https://letsencrypt.org) certificates generated through Træfik).
|
The configuration file allows managing both backends/frontends and HTTPS certificates (which are not [Let's Encrypt](https://letsencrypt.org) certificates generated through Traefik).
|
||||||
|
|
||||||
TOML templating can be used if rules are not defined in the Træfik configuration file.
|
TOML templating can be used if rules are not defined in the Traefik configuration file.
|
||||||
|
|
||||||
### Rules in Træfik Configuration File
|
### Rules in Traefik Configuration File
|
||||||
|
|
||||||
Add your configuration at the end of the global configuration file `traefik.toml`:
|
Add your configuration at the end of the global configuration file `traefik.toml`:
|
||||||
|
|
||||||
|
@ -245,11 +248,11 @@ defaultEntryPoints = ["http", "https"]
|
||||||
It's recommended to use the file provider to declare certificates.
|
It's recommended to use the file provider to declare certificates.
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
TOML templating cannot be used if rules are defined in the Træfik configuration file.
|
TOML templating cannot be used if rules are defined in the Traefik configuration file.
|
||||||
|
|
||||||
### Rules in Dedicated Files
|
### Rules in Dedicated Files
|
||||||
|
|
||||||
Træfik allows defining rules in one or more separate files.
|
Traefik allows defining rules in one or more separate files.
|
||||||
|
|
||||||
#### One Separate File
|
#### One Separate File
|
||||||
|
|
||||||
|
@ -270,7 +273,7 @@ defaultEntryPoints = ["http", "https"]
|
||||||
watch = true
|
watch = true
|
||||||
```
|
```
|
||||||
|
|
||||||
The option `file.watch` allows Træfik to watch file changes automatically.
|
The option `file.watch` allows Traefik to watch file changes automatically.
|
||||||
|
|
||||||
#### Multiple Separated Files
|
#### Multiple Separated Files
|
||||||
|
|
||||||
|
@ -282,7 +285,7 @@ You could have multiple `.toml` files in a directory (and recursively in its sub
|
||||||
watch = true
|
watch = true
|
||||||
```
|
```
|
||||||
|
|
||||||
The option `file.watch` allows Træfik to watch file changes automatically.
|
The option `file.watch` allows Traefik to watch file changes automatically.
|
||||||
|
|
||||||
#### Separate Files Content
|
#### Separate Files Content
|
||||||
|
|
||||||
|
@ -320,9 +323,9 @@ Backends, Frontends and TLS certificates are defined one at time, as described i
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
TOML templating can only be used **if rules are defined in one or more separate files**.
|
TOML templating can only be used **if rules are defined in one or more separate files**.
|
||||||
Templating will not work in the Træfik configuration file.
|
Templating will not work in the Traefik configuration file.
|
||||||
|
|
||||||
Træfik allows using TOML templating.
|
Traefik allows using TOML templating.
|
||||||
|
|
||||||
Thus, it's possible to define easily lot of Backends, Frontends and TLS certificates as described in the file `template-rules.toml` :
|
Thus, it's possible to define easily lot of Backends, Frontends and TLS certificates as described in the file `template-rules.toml` :
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Kubernetes Ingress Provider
|
# Kubernetes Ingress Provider
|
||||||
|
|
||||||
Træfik can be configured to use Kubernetes Ingress as a provider.
|
Traefik can be configured to use Kubernetes Ingress as a provider.
|
||||||
|
|
||||||
See also [Kubernetes user guide](/user-guide/kubernetes).
|
See also [Kubernetes user guide](/user-guide/kubernetes).
|
||||||
|
|
||||||
|
@ -146,31 +146,38 @@ If either of those configuration options exist, then the backend communication p
|
||||||
|
|
||||||
The following general annotations are applicable on the Ingress object:
|
The following general annotations are applicable on the Ingress object:
|
||||||
|
|
||||||
| Annotation | Description |
|
| Annotation | Description |
|
||||||
|---------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.ingress.kubernetes.io/buffering: <YML>` | (3) See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (1) |
|
||||||
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | (1) See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | See [custom error pages](/configuration/commons/#custom-error-pages) section. (2) |
|
||||||
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
|
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
|
||||||
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`. |
|
| `traefik.ingress.kubernetes.io/pass-client-tls-cert: <YML>` | Forward the client certificate following the configuration in YAML. (3) |
|
||||||
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
|
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`.(DEPRECATED) |
|
||||||
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
|
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
|
||||||
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | (2) See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
|
||||||
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
|
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | See [rate limiting](/configuration/commons/#rate-limiting) section. (4) |
|
||||||
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
|
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
|
||||||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
|
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
|
||||||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
|
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
|
||||||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
|
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
|
||||||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines). Note: ReplacePath is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`. |
|
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Adds a [request modifier](/basics/#modifiers) to the backend request. |
|
||||||
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. |
|
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
|
||||||
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (6). |
|
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Overrides the default frontend rule type. Only path-related matchers can be specified [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines).(5) |
|
||||||
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
|
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. |
|
||||||
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy-depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.ingress.kubernetes.io/service-weights: <YML>` | Set ingress backend weights specified as percentage or decimal numbers in YAML. (6) |
|
||||||
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy-excludedIPs=127.0.0. 1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (7). |
|
||||||
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) |
|
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
|
||||||
| `traefik.ingress.kubernetes.io/service-weights: <YML>` | Set ingress backend weights specified as percentage or decimal numbers in YAML. (5) |
|
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy-depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
||||||
| `ingress.kubernetes.io/protocol: <NAME>` | Set the protocol Traefik will use to communicate with pods. |
|
| `traefik.ingress.kubernetes.io/whiteList-ipstrategy-excludedIPs=127.0.0. 1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
||||||
|
| `ingress.kubernetes.io/protocol: <NAME>` | Set the protocol Traefik will use to communicate with pods. |
|
||||||
|
|
||||||
<1> `traefik.ingress.kubernetes.io/error-pages` example:
|
<1> `traefik.ingress.kubernetes.io/app-root`:
|
||||||
|
Non-root paths will not be affected by this annotation and handled normally.
|
||||||
|
This annotation may not be combined with other redirect annotations.
|
||||||
|
Trying to do so will result in the other redirects being ignored.
|
||||||
|
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
|
||||||
|
|
||||||
|
<2> `traefik.ingress.kubernetes.io/error-pages` example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
foo:
|
foo:
|
||||||
|
@ -186,7 +193,31 @@ fii:
|
||||||
query: /bir
|
query: /bir
|
||||||
```
|
```
|
||||||
|
|
||||||
<2> `traefik.ingress.kubernetes.io/rate-limit` example:
|
<3> `traefik.ingress.kubernetes.io/pass-client-tls-cert` example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# add escaped pem in the `X-Forwarded-Tls-Client-Cert` header
|
||||||
|
pem: true
|
||||||
|
# add escaped certificate following infos in the `X-Forwarded-Tls-Client-Cert-Infos` header
|
||||||
|
infos:
|
||||||
|
notafter: true
|
||||||
|
notbefore: true
|
||||||
|
sans: true
|
||||||
|
subject:
|
||||||
|
country: true
|
||||||
|
province: true
|
||||||
|
locality: true
|
||||||
|
organization: true
|
||||||
|
commonname: true
|
||||||
|
serialnumber: true
|
||||||
|
```
|
||||||
|
|
||||||
|
If `pem` is set, it will add a `X-Forwarded-Tls-Client-Cert` header that contains the escaped pem as value.
|
||||||
|
If at least one flag of the `infos` part is set, it will add a `X-Forwarded-Tls-Client-Cert-Infos` header that contains an escaped string composed of the client certificate data selected by the infos flags.
|
||||||
|
This infos part is composed like the following example (not escaped):
|
||||||
|
```Subject="C=FR,ST=SomeState,L=Lyon,O=Cheese,CN=*.cheese.org",NB=1531900816,NA=1563436816,SAN=*.cheese.org,*.cheese.net,cheese.in,test@cheese.org,test@cheese.net,10.0.1.0,10.0.1.2```
|
||||||
|
|
||||||
|
<4> `traefik.ingress.kubernetes.io/rate-limit` example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
extractorfunc: client.ip
|
extractorfunc: client.ip
|
||||||
|
@ -201,16 +232,10 @@ rateset:
|
||||||
burst: 18
|
burst: 18
|
||||||
```
|
```
|
||||||
|
|
||||||
<3> `traefik.ingress.kubernetes.io/rule-type`
|
<5> `traefik.ingress.kubernetes.io/rule-type`
|
||||||
Note: `ReplacePath` is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`.
|
Note: `ReplacePath` is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`.
|
||||||
|
|
||||||
<4> `traefik.ingress.kubernetes.io/app-root`:
|
<6> `traefik.ingress.kubernetes.io/service-weights`:
|
||||||
Non-root paths will not be affected by this annotation and handled normally.
|
|
||||||
This annotation may not be combined with other redirect annotations.
|
|
||||||
Trying to do so will result in the other redirects being ignored.
|
|
||||||
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
|
|
||||||
|
|
||||||
<5> `traefik.ingress.kubernetes.io/service-weights`:
|
|
||||||
Service weights enable to split traffic across multiple backing services in a fine-grained manner.
|
Service weights enable to split traffic across multiple backing services in a fine-grained manner.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -238,7 +263,7 @@ For each path definition, this annotation will fail if:
|
||||||
|
|
||||||
See also the [user guide section traffic splitting](/user-guide/kubernetes/#traffic-splitting).
|
See also the [user guide section traffic splitting](/user-guide/kubernetes/#traffic-splitting).
|
||||||
|
|
||||||
<6> `traefik.ingress.kubernetes.io/whitelist-source-range`:
|
<7> `traefik.ingress.kubernetes.io/whitelist-source-range`:
|
||||||
All source IPs are permitted if the list is empty or a single range is ill-formatted.
|
All source IPs are permitted if the list is empty or a single range is ill-formatted.
|
||||||
Please note, you may have to set `service.spec.externalTrafficPolicy` to the value `Local` to preserve the source IP of the request for filtering.
|
Please note, you may have to set `service.spec.externalTrafficPolicy` to the value `Local` to preserve the source IP of the request for filtering.
|
||||||
Please see [this link](https://kubernetes.io/docs/tutorials/services/source-ip/) for more information.
|
Please see [this link](https://kubernetes.io/docs/tutorials/services/source-ip/) for more information.
|
||||||
|
@ -254,6 +279,7 @@ The following annotations are applicable on the Service object associated with a
|
||||||
| `traefik.ingress.kubernetes.io/buffering: <YML>` | (1) See the [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.ingress.kubernetes.io/buffering: <YML>` | (1) See the [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.ingress.kubernetes.io/affinity: "true"` | Enable backend sticky sessions. |
|
| `traefik.ingress.kubernetes.io/affinity: "true"` | Enable backend sticky sessions. |
|
||||||
| `traefik.ingress.kubernetes.io/circuit-breaker-expression: <expression>` | Set the circuit breaker expression for the backend. |
|
| `traefik.ingress.kubernetes.io/circuit-breaker-expression: <expression>` | Set the circuit breaker expression for the backend. |
|
||||||
|
| `traefik.ingress.kubernetes.io/responseforwarding-flushinterval: "10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.ingress.kubernetes.io/load-balancer-method: drr` | Override the default `wrr` load balancer algorithm. |
|
| `traefik.ingress.kubernetes.io/load-balancer-method: drr` | Override the default `wrr` load balancer algorithm. |
|
||||||
| `traefik.ingress.kubernetes.io/max-conn-amount: "10"` | Sets the maximum number of simultaneous connections to the backend.<br>Must be used in conjunction with the label below to take effect. |
|
| `traefik.ingress.kubernetes.io/max-conn-amount: "10"` | Sets the maximum number of simultaneous connections to the backend.<br>Must be used in conjunction with the label below to take effect. |
|
||||||
| `traefik.ingress.kubernetes.io/max-conn-extractor-func: client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
| `traefik.ingress.kubernetes.io/max-conn-extractor-func: client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||||
|
@ -298,7 +324,7 @@ The following security annotations are applicable on the Ingress object:
|
||||||
| `ingress.kubernetes.io/hsts-preload: "true"` | Adds the preload flag to the HSTS header. |
|
| `ingress.kubernetes.io/hsts-preload: "true"` | Adds the preload flag to the HSTS header. |
|
||||||
| `ingress.kubernetes.io/is-development: "false"` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `ingress.kubernetes.io/is-development: "false"` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `ingress.kubernetes.io/proxy-headers: EXPR` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
|
| `ingress.kubernetes.io/proxy-headers: EXPR` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
|
||||||
| `ingress.kubernetes.io/public-key: VALUE` | Adds pinned HTST public key header. |
|
| `ingress.kubernetes.io/public-key: VALUE` | Adds HPKP header. |
|
||||||
| `ingress.kubernetes.io/referrer-policy: VALUE` | Adds referrer policy header. |
|
| `ingress.kubernetes.io/referrer-policy: VALUE` | Adds referrer policy header. |
|
||||||
| `ingress.kubernetes.io/ssl-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `ingress.kubernetes.io/ssl-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `ingress.kubernetes.io/ssl-temporary-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `ingress.kubernetes.io/ssl-temporary-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
@ -358,5 +384,5 @@ This ingress follows the [Global Default Backend](https://kubernetes.io/docs/con
|
||||||
This will allow users to create a "default backend" that will match all unmatched requests.
|
This will allow users to create a "default backend" that will match all unmatched requests.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Due to Træfik's use of priorities, you may have to set this ingress priority lower than other ingresses in your environment, to avoid this global ingress from satisfying requests that _could_ match other ingresses.
|
Due to Traefik's use of priorities, you may have to set this ingress priority lower than other ingresses in your environment, to avoid this global ingress from satisfying requests that _could_ match other ingresses.
|
||||||
To do this, use the `traefik.ingress.kubernetes.io/priority` annotation (as seen in [General Annotations](/configuration/backends/kubernetes/#general-annotations)) on your ingresses accordingly.
|
To do this, use the `traefik.ingress.kubernetes.io/priority` annotation (as seen in [General Annotations](/configuration/backends/kubernetes/#general-annotations)) on your ingresses accordingly.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Marathon Provider
|
# Marathon Provider
|
||||||
|
|
||||||
Træfik can be configured to use Marathon as a provider.
|
Traefik can be configured to use Marathon as a provider.
|
||||||
|
|
||||||
See also [Marathon user guide](/user-guide/marathon).
|
See also [Marathon user guide](/user-guide/marathon).
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ The following labels can be defined on Marathon applications. They adjust the be
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default base domain used for the frontend rules. |
|
| `traefik.domain` | Sets the default base domain used for the frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Traefik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
||||||
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
|
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
||||||
|
@ -208,6 +208,7 @@ The following labels can be defined on Marathon applications. They adjust the be
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
||||||
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
||||||
|
@ -290,7 +291,7 @@ The following labels can be defined on Marathon applications. They adjust the be
|
||||||
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Mesos Generic Provider
|
# Mesos Generic Provider
|
||||||
|
|
||||||
Træfik can be configured to use Mesos as a provider.
|
Traefik can be configured to use Mesos as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
@ -109,7 +109,7 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Traefik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the application exposes multiple ports. |
|
| `traefik.port=80` | Registers this port. Useful when the application exposes multiple ports. |
|
||||||
| `traefik.portName=web` | Registers port by name in the application's ports array. Useful when the application exposes multiple ports. |
|
| `traefik.portName=web` | Registers port by name in the application's ports array. Useful when the application exposes multiple ports. |
|
||||||
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
|
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
|
||||||
|
@ -122,6 +122,7 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
|
||||||
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
|
||||||
|
@ -203,7 +204,7 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
|
||||||
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Rancher Provider
|
# Rancher Provider
|
||||||
|
|
||||||
Træfik can be configured to use Rancher as a provider.
|
Traefik can be configured to use Rancher as a provider.
|
||||||
|
|
||||||
## Global Configuration
|
## Global Configuration
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ Labels can be used on task containers to override default behavior:
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
| `traefik.domain` | Sets the default base domain for the frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Traefik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container. |
|
| `traefik.weight=10` | Assigns this weight to the container. |
|
||||||
|
@ -152,6 +152,7 @@ Labels can be used on task containers to override default behavior:
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
|
| `traefik.backend.responseForwarding.flushInterval=10ms` | Defines the interval between two flushes when forwarding response from backend to client. |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
|
||||||
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
|
||||||
| `traefik.backend.healthcheck.timeout=3s ` | Defines the health check request timeout. |
|
| `traefik.backend.healthcheck.timeout=3s ` | Defines the health check request timeout. |
|
||||||
|
@ -232,7 +233,7 @@ Labels can be used on task containers to override default behavior:
|
||||||
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
|
||||||
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
|
||||||
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Rest Provider
|
# Rest Provider
|
||||||
|
|
||||||
Træfik can be configured:
|
Traefik can be configured:
|
||||||
|
|
||||||
- using a RESTful api.
|
- using a RESTful api.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Azure Service Fabric Provider
|
# Azure Service Fabric Provider
|
||||||
|
|
||||||
Træfik can be configured to use Azure Service Fabric as a provider.
|
Traefik can be configured to use Azure Service Fabric as a provider.
|
||||||
|
|
||||||
See [this repository for an example deployment package and further documentation.](https://aka.ms/traefikonsf)
|
See [this repository for an example deployment package and further documentation.](https://aka.ms/traefikonsf)
|
||||||
|
|
||||||
|
@ -47,13 +47,13 @@ refreshSeconds = 10
|
||||||
|
|
||||||
## Labels
|
## Labels
|
||||||
|
|
||||||
The provider uses labels to configure how services are exposed through Træfik.
|
The provider uses labels to configure how services are exposed through Traefik.
|
||||||
These can be set using Extensions and the Property Manager API
|
These can be set using Extensions and the Property Manager API
|
||||||
|
|
||||||
#### Extensions
|
#### Extensions
|
||||||
|
|
||||||
Set labels with extensions through the services `ServiceManifest.xml` file.
|
Set labels with extensions through the services `ServiceManifest.xml` file.
|
||||||
Here is an example of an extension setting Træfik labels:
|
Here is an example of an extension setting Traefik labels:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<StatelessServiceType ServiceTypeName="WebServiceType">
|
<StatelessServiceType ServiceTypeName="WebServiceType">
|
||||||
|
@ -96,9 +96,9 @@ Labels, set through extensions or the property manager, can be used on services
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.enable=false` | Disable this container in Træfik |
|
| `traefik.enable=false` | Disable this container in Traefik |
|
||||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
| `traefik.servicefabric.groupname` | Group all services with the same name into a single backend in Træfik |
|
| `traefik.servicefabric.groupname` | Group all services with the same name into a single backend in Traefik |
|
||||||
| `traefik.servicefabric.groupweight` | Set the weighting of the current services nodes in the backend group |
|
| `traefik.servicefabric.groupweight` | Set the weighting of the current services nodes in the backend group |
|
||||||
| `traefik.servicefabric.enablelabeloverrides` | Toggle whether labels can be overridden using the Service Fabric Property Manager API |
|
| `traefik.servicefabric.enablelabeloverrides` | Toggle whether labels can be overridden using the Service Fabric Property Manager API |
|
||||||
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
|
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
|
||||||
|
@ -155,6 +155,6 @@ Labels, set through extensions or the property manager, can be used on services
|
||||||
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
|
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
|
||||||
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
|
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
|
||||||
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
|
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
|
||||||
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
|
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
|
||||||
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
|
||||||
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Zookeeper Provider
|
# Zookeeper Provider
|
||||||
|
|
||||||
Træfik can be configured to use Zookeeper as a provider.
|
Traefik can be configured to use Zookeeper as a provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -20,6 +20,13 @@
|
||||||
#
|
#
|
||||||
# checkNewVersion = false
|
# checkNewVersion = false
|
||||||
|
|
||||||
|
# Tells traefik whether it should keep the trailing slashes in the paths (e.g. /paths/) or redirect to the no trailing slash paths instead (/paths).
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: false
|
||||||
|
#
|
||||||
|
# keepTrailingSlash = false
|
||||||
|
|
||||||
# Providers throttle duration.
|
# Providers throttle duration.
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
|
@ -76,12 +83,31 @@ If you encounter 'too many open files' errors, you can either increase this valu
|
||||||
- `defaultEntryPoints`: Entrypoints to be used by frontends that do not specify any entrypoint.
|
- `defaultEntryPoints`: Entrypoints to be used by frontends that do not specify any entrypoint.
|
||||||
Each frontend can specify its own entrypoints.
|
Each frontend can specify its own entrypoints.
|
||||||
|
|
||||||
|
- `keepTrailingSlash`: Tells Træfik whether it should keep the trailing slashes that might be present in the paths of incoming requests (true), or if it should redirect to the slashless version of the URL (default behavior: false)
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Beware that the value of `keepTrailingSlash` can have a significant impact on the way your frontend rules are interpreted.
|
||||||
|
The table below tries to sum up several behaviors depending on requests/configurations.
|
||||||
|
The current default behavior is deprecated and kept for compatibility reasons.
|
||||||
|
As a consequence, we encourage you to set `keepTrailingSlash` to true.
|
||||||
|
|
||||||
|
| Incoming request | keepTrailingSlash | Path:{value} | Behavior
|
||||||
|
|----------------------|-------------------|--------------|----------------------------|
|
||||||
|
| http://foo.com/path/ | false | Path:/path/ | Proceeds with the request |
|
||||||
|
| http://foo.com/path/ | false | Path:/path | 301 to http://foo.com/path |
|
||||||
|
| http://foo.com/path | false | Path:/path/ | Proceeds with the request |
|
||||||
|
| http://foo.com/path | false | Path:/path | Proceeds with the request |
|
||||||
|
| http://foo.com/path/ | true | Path:/path/ | Proceeds with the request |
|
||||||
|
| http://foo.com/path/ | true | Path:/path | 404 |
|
||||||
|
| http://foo.com/path | true | Path:/path/ | 404 |
|
||||||
|
| http://foo.com/path | true | Path:/path | Proceeds with the request |
|
||||||
|
|
||||||
|
|
||||||
## Constraints
|
## Constraints
|
||||||
|
|
||||||
In a micro-service architecture, with a central service discovery, setting constraints limits Træfik scope to a smaller number of routes.
|
In a micro-service architecture, with a central service discovery, setting constraints limits Traefik scope to a smaller number of routes.
|
||||||
|
|
||||||
Træfik filters services according to service attributes/tags set in your providers.
|
Traefik filters services according to service attributes/tags set in your providers.
|
||||||
|
|
||||||
Supported filters:
|
Supported filters:
|
||||||
|
|
||||||
|
@ -202,7 +228,7 @@ These can "burst" up to 10 and 200 in each period respectively.
|
||||||
## Buffering
|
## Buffering
|
||||||
|
|
||||||
In some cases request/buffering can be enabled for a specific backend.
|
In some cases request/buffering can be enabled for a specific backend.
|
||||||
By enabling this, Træfik will read the entire request into memory (possibly buffering large requests into disk) and will reject requests that are over a specified limit.
|
By enabling this, Traefik will read the entire request into memory (possibly buffering large requests into disk) and will reject requests that are over a specified limit.
|
||||||
This may help services deal with large data (multipart/form-data for example) more efficiently and should minimise time spent when sending data to a backend server.
|
This may help services deal with large data (multipart/form-data for example) more efficiently and should minimise time spent when sending data to a backend server.
|
||||||
|
|
||||||
For more information please check [oxy/buffer](http://godoc.org/github.com/vulcand/oxy/buffer) documentation.
|
For more information please check [oxy/buffer](http://godoc.org/github.com/vulcand/oxy/buffer) documentation.
|
||||||
|
|
|
@ -245,8 +245,8 @@ If you need to add or remove TLS certificates while Traefik is started, Dynamic
|
||||||
## TLS Mutual Authentication
|
## TLS Mutual Authentication
|
||||||
|
|
||||||
TLS Mutual Authentication can be `optional` or not.
|
TLS Mutual Authentication can be `optional` or not.
|
||||||
If it's `optional`, Træfik will authorize connection with certificates not signed by a specified Certificate Authority (CA).
|
If it's `optional`, Traefik will authorize connection with certificates not signed by a specified Certificate Authority (CA).
|
||||||
Otherwise, Træfik will only accept clients that present a certificate signed by a specified Certificate Authority (CA).
|
Otherwise, Traefik will only accept clients that present a certificate signed by a specified Certificate Authority (CA).
|
||||||
`ClientCA.files` can be configured with multiple `CA:s` in the same file or use multiple files containing one or several `CA:s`.
|
`ClientCA.files` can be configured with multiple `CA:s` in the same file or use multiple files containing one or several `CA:s`.
|
||||||
The `CA:s` has to be in PEM format.
|
The `CA:s` has to be in PEM format.
|
||||||
|
|
||||||
|
@ -594,7 +594,7 @@ To enable [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-protoco
|
||||||
Only IPs in `trustedIPs` will lead to remote client address replacement: you should declare your load-balancer IP or CIDR range here (in testing environment, you can trust everyone using `insecure = true`).
|
Only IPs in `trustedIPs` will lead to remote client address replacement: you should declare your load-balancer IP or CIDR range here (in testing environment, you can trust everyone using `insecure = true`).
|
||||||
|
|
||||||
!!! danger
|
!!! danger
|
||||||
When queuing Træfik behind another load-balancer, be sure to carefully configure Proxy Protocol on both sides.
|
When queuing Traefik behind another load-balancer, be sure to carefully configure Proxy Protocol on both sides.
|
||||||
Otherwise, it could introduce a security risk in your system by forging requests.
|
Otherwise, it could introduce a security risk in your system by forging requests.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|
|
@ -248,7 +248,7 @@ RetryAttempts
|
||||||
|
|
||||||
### CLF - Common Log Format
|
### CLF - Common Log Format
|
||||||
|
|
||||||
By default, Træfik use the CLF (`common`) as access log format.
|
By default, Traefik use the CLF (`common`) as access log format.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<remote_IP_address> - <client_user_name_if_available> [<timestamp>] "<request_method> <request_path> <request_protocol>" <origin_server_HTTP_status> <origin_server_content_size> "<request_referrer>" "<request_user_agent>" <number_of_requests_received_since_Traefik_started> "<Traefik_frontend_name>" "<Traefik_backend_URL>" <request_duration_in_ms>ms
|
<remote_IP_address> - <client_user_name_if_available> [<timestamp>] "<request_method> <request_path> <request_protocol>" <origin_server_HTTP_status> <origin_server_content_size> "<request_referrer>" "<request_user_agent>" <number_of_requests_received_since_Traefik_started> "<Traefik_frontend_name>" "<Traefik_backend_URL>" <request_duration_in_ms>ms
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
| Path | Method | Description |
|
| Path | Method | Description |
|
||||||
|---------|---------------|----------------------------------------------------------------------------------------------------|
|
|---------|---------------|----------------------------------------------------------------------------------------------------|
|
||||||
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Træfik process liveness. Return a code `200` with the content: `OK` |
|
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
|
||||||
|
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
|
|
|
@ -4,7 +4,7 @@ The tracing system allows developers to visualize call flows in their infrastruc
|
||||||
|
|
||||||
We use [OpenTracing](http://opentracing.io). It is an open standard designed for distributed tracing.
|
We use [OpenTracing](http://opentracing.io). It is an open standard designed for distributed tracing.
|
||||||
|
|
||||||
Træfik supports three tracing backends: Jaeger, Zipkin and DataDog.
|
Traefik supports three tracing backends: Jaeger, Zipkin and DataDog.
|
||||||
|
|
||||||
## Jaeger
|
## Jaeger
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ Træfik supports three tracing backends: Jaeger, Zipkin and DataDog.
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
Træfik is only able to send data over compact thrift protocol to the [Jaeger agent](https://www.jaegertracing.io/docs/deployment/#agent).
|
Traefik is only able to send data over compact thrift protocol to the [Jaeger agent](https://www.jaegertracing.io/docs/deployment/#agent).
|
||||||
|
|
||||||
## Zipkin
|
## Zipkin
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="img/traefik.logo.png" alt="Træfik" title="Træfik" />
|
<img src="img/traefik.logo.png" alt="Traefik" title="Traefik" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
|
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
|
||||||
|
@ -10,9 +10,9 @@
|
||||||
[![Twitter](https://img.shields.io/twitter/follow/traefik.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefik)
|
[![Twitter](https://img.shields.io/twitter/follow/traefik.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefik)
|
||||||
|
|
||||||
|
|
||||||
Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
||||||
Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
|
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
|
||||||
Pointing Træfik at your orchestrator should be the _only_ configuration step you need.
|
Pointing Traefik at your orchestrator should be the _only_ configuration step you need.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ Now you want users to access these microservices, and you need a reverse proxy.
|
||||||
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
|
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
|
||||||
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
|
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
|
||||||
|
|
||||||
**This is when Træfik can help you!**
|
**This is when Traefik can help you!**
|
||||||
|
|
||||||
Træfik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
|
Traefik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
|
||||||
|
|
||||||
**Run Træfik and let it do the work for you!**
|
**Run Traefik and let it do the work for you!**
|
||||||
_(But if you'd rather configure some of your routes manually, Træfik supports that too!)_
|
_(But if you'd rather configure some of your routes manually, Traefik supports that too!)_
|
||||||
|
|
||||||
![Architecture](img/architecture.png)
|
![Architecture](img/architecture.png)
|
||||||
|
|
||||||
|
@ -62,15 +62,15 @@ _(But if you'd rather configure some of your routes manually, Træfik supports t
|
||||||
- [File](/configuration/backends/file/)
|
- [File](/configuration/backends/file/)
|
||||||
- [Rest](/configuration/backends/rest/)
|
- [Rest](/configuration/backends/rest/)
|
||||||
|
|
||||||
## The Træfik Quickstart (Using Docker)
|
## The Traefik Quickstart (Using Docker)
|
||||||
|
|
||||||
In this quickstart, we'll use [Docker compose](https://docs.docker.com/compose) to create our demo infrastructure.
|
In this quickstart, we'll use [Docker compose](https://docs.docker.com/compose) to create our demo infrastructure.
|
||||||
|
|
||||||
To save some time, you can clone [Træfik's repository](https://github.com/containous/traefik) and use the quickstart files located in the [examples/quickstart](https://github.com/containous/traefik/tree/master/examples/quickstart/) directory.
|
To save some time, you can clone [Traefik's repository](https://github.com/containous/traefik) and use the quickstart files located in the [examples/quickstart](https://github.com/containous/traefik/tree/master/examples/quickstart/) directory.
|
||||||
|
|
||||||
### 1 — Launch Træfik — Tell It to Listen to Docker
|
### 1 — Launch Traefik — Tell It to Listen to Docker
|
||||||
|
|
||||||
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Træfik image:
|
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3'
|
version: '3'
|
||||||
|
@ -78,7 +78,7 @@ version: '3'
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik # The official Traefik docker image
|
image: traefik # The official Traefik docker image
|
||||||
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
|
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
|
||||||
ports:
|
ports:
|
||||||
- "80:80" # The HTTP port
|
- "80:80" # The HTTP port
|
||||||
- "8080:8080" # The Web UI (enabled by --api)
|
- "8080:8080" # The Web UI (enabled by --api)
|
||||||
|
@ -90,7 +90,7 @@ services:
|
||||||
Enabling the Web UI with the `--api` flag might expose configuration elements. You can read more about this on the [API/Dashboard's Security section](/configuration/api#security).
|
Enabling the Web UI with the `--api` flag might expose configuration elements. You can read more about this on the [API/Dashboard's Security section](/configuration/api#security).
|
||||||
|
|
||||||
|
|
||||||
**That's it. Now you can launch Træfik!**
|
**That's it. Now you can launch Traefik!**
|
||||||
|
|
||||||
Start your `reverse-proxy` with the following command:
|
Start your `reverse-proxy` with the following command:
|
||||||
|
|
||||||
|
@ -98,18 +98,18 @@ Start your `reverse-proxy` with the following command:
|
||||||
docker-compose up -d reverse-proxy
|
docker-compose up -d reverse-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Træfik's dashboard (we'll go back there once we have launched a service in step 2).
|
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Traefik's dashboard (we'll go back there once we have launched a service in step 2).
|
||||||
|
|
||||||
### 2 — Launch a Service — Træfik Detects It and Creates a Route for You
|
### 2 — Launch a Service — Traefik Detects It and Creates a Route for You
|
||||||
|
|
||||||
Now that we have a Træfik instance up and running, we will deploy new services.
|
Now that we have a Traefik instance up and running, we will deploy new services.
|
||||||
|
|
||||||
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# ...
|
# ...
|
||||||
whoami:
|
whoami:
|
||||||
image: emilevauge/whoami # A container that exposes an API to show its IP address
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
labels:
|
labels:
|
||||||
- "traefik.frontend.rule=Host:whoami.docker.localhost"
|
- "traefik.frontend.rule=Host:whoami.docker.localhost"
|
||||||
```
|
```
|
||||||
|
@ -122,7 +122,7 @@ Start the `whoami` service with the following command:
|
||||||
docker-compose up -d whoami
|
docker-compose up -d whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Træfik has automatically detected the new container and updated its own configuration.
|
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||||
|
|
||||||
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
||||||
|
|
||||||
|
@ -145,9 +145,9 @@ Run more instances of your `whoami` service with the following command:
|
||||||
docker-compose scale whoami=2
|
docker-compose scale whoami=2
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Træfik has automatically detected the new instance of the container.
|
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new instance of the container.
|
||||||
|
|
||||||
Finally, see that Træfik load-balances between the two instances of your services by running twice the following command:
|
Finally, see that Traefik load-balances between the two instances of your services by running twice the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||||
|
@ -167,22 +167,22 @@ IP: 172.27.0.4
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4 — Enjoy Træfik's Magic
|
### 4 — Enjoy Traefik's Magic
|
||||||
|
|
||||||
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](/) and let Træfik work for you!
|
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](/) and let Traefik work for you!
|
||||||
Whatever your infrastructure is, there is probably [an available Træfik provider](/#supported-providers) that will do the job.
|
Whatever your infrastructure is, there is probably [an available Traefik provider](/#supported-providers) that will do the job.
|
||||||
|
|
||||||
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](/user-guide/docker-and-lets-encrypt/).
|
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Traefik's let's encrypt integration](/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](/user-guide/docker-and-lets-encrypt/).
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at [GopherCon 2017](https://gophercon.com).
|
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at [GopherCon 2017](https://gophercon.com).
|
||||||
You will learn Træfik basics in less than 10 minutes.
|
You will learn Traefik basics in less than 10 minutes.
|
||||||
|
|
||||||
[![Traefik GopherCon 2017](https://img.youtube.com/vi/RgudiksfL-k/0.jpg)](https://www.youtube.com/watch?v=RgudiksfL-k)
|
[![Traefik GopherCon 2017](https://img.youtube.com/vi/RgudiksfL-k/0.jpg)](https://www.youtube.com/watch?v=RgudiksfL-k)
|
||||||
|
|
||||||
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
||||||
You will learn fundamental Træfik features and see some demos with Kubernetes.
|
You will learn fundamental Traefik features and see some demos with Kubernetes.
|
||||||
|
|
||||||
[![Traefik ContainerCamp UK](https://img.youtube.com/vi/aFtpIShV60I/0.jpg)](https://www.youtube.com/watch?v=aFtpIShV60I)
|
[![Traefik ContainerCamp UK](https://img.youtube.com/vi/aFtpIShV60I/0.jpg)](https://www.youtube.com/watch?v=aFtpIShV60I)
|
||||||
|
|
||||||
|
@ -217,5 +217,5 @@ Reported vulnerabilities can be found on
|
||||||
|
|
||||||
### Report a Vulnerability
|
### Report a Vulnerability
|
||||||
|
|
||||||
We want to keep Træfik safe for everyone.
|
We want to keep Traefik safe for everyone.
|
||||||
If you've discovered a security vulnerability in Træfik, we appreciate your help in disclosing it to us in a responsible manner, using [this form](https://security.traefik.io).
|
If you've discovered a security vulnerability in Traefik, we appreciate your help in disclosing it to us in a responsible manner, using [this form](https://security.traefik.io).
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
# Clustering / High Availability on Docker Swarm with Consul
|
# Clustering / High Availability on Docker Swarm with Consul
|
||||||
|
|
||||||
This guide explains how to use Træfik in high availability mode in a Docker Swarm and with Let's Encrypt.
|
This guide explains how to use Traefik in high availability mode in a Docker Swarm and with Let's Encrypt.
|
||||||
|
|
||||||
Why do we need Træfik in cluster mode? Running multiple instances should work out of the box?
|
Why do we need Traefik in cluster mode? Running multiple instances should work out of the box?
|
||||||
|
|
||||||
If you want to use Let's Encrypt with Træfik, sharing configuration or TLS certificates between many Træfik instances, you need Træfik cluster/HA.
|
If you want to use Let's Encrypt with Traefik, sharing configuration or TLS certificates between many Traefik instances, you need Traefik cluster/HA.
|
||||||
|
|
||||||
Ok, could we mount a shared volume used by all my instances? Yes, you can, but it will not work.
|
Ok, could we mount a shared volume used by all my instances? Yes, you can, but it will not work.
|
||||||
When you use Let's Encrypt, you need to store certificates, but not only.
|
When you use Let's Encrypt, you need to store certificates, but not only.
|
||||||
When Træfik generates a new certificate, it configures a challenge and once Let's Encrypt will verify the ownership of the domain, it will ping back the challenge.
|
When Traefik generates a new certificate, it configures a challenge and once Let's Encrypt will verify the ownership of the domain, it will ping back the challenge.
|
||||||
If the challenge is not known by other Træfik instances, the validation will fail.
|
If the challenge is not known by other Traefik instances, the validation will fail.
|
||||||
|
|
||||||
For more information about the challenge: [Automatic Certificate Management Environment (ACME)](https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http-challenge)
|
For more information about the challenge: [Automatic Certificate Management Environment (ACME)](https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http-challenge)
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@ For more information about the challenge: [Automatic Certificate Management Envi
|
||||||
|
|
||||||
You will need a working Docker Swarm cluster.
|
You will need a working Docker Swarm cluster.
|
||||||
|
|
||||||
## Træfik configuration
|
## Traefik configuration
|
||||||
|
|
||||||
In this guide, we will not use a TOML configuration file, but only command line flag.
|
In this guide, we will not use a TOML configuration file, but only command line flag.
|
||||||
With that, we can use the base image without mounting configuration file or building custom image.
|
With that, we can use the base image without mounting configuration file or building custom image.
|
||||||
|
|
||||||
What Træfik should do:
|
What Traefik should do:
|
||||||
|
|
||||||
- Listen to 80 and 443
|
- Listen to 80 and 443
|
||||||
- Redirect HTTP traffic to HTTPS
|
- Redirect HTTP traffic to HTTPS
|
||||||
|
@ -64,7 +64,7 @@ Let's Encrypt needs 4 parameters: an TLS entry point to listen to, a non-TLS ent
|
||||||
|
|
||||||
To enable Let's Encrypt support, you need to add `--acme` flag.
|
To enable Let's Encrypt support, you need to add `--acme` flag.
|
||||||
|
|
||||||
Now, Træfik needs to know where to store the certificates, we can choose between a key in a Key-Value store, or a file path: `--acme.storage=my/key` or `--acme.storage=/path/to/acme.json`.
|
Now, Traefik needs to know where to store the certificates, we can choose between a key in a Key-Value store, or a file path: `--acme.storage=my/key` or `--acme.storage=/path/to/acme.json`.
|
||||||
|
|
||||||
The `acme.httpChallenge.entryPoint` flag enables the `HTTP-01` challenge and specifies the entryPoint to use during the challenges.
|
The `acme.httpChallenge.entryPoint` flag enables the `HTTP-01` challenge and specifies the entryPoint to use during the challenges.
|
||||||
|
|
||||||
|
@ -143,9 +143,9 @@ networks:
|
||||||
|
|
||||||
## Migrate configuration to Consul
|
## Migrate configuration to Consul
|
||||||
|
|
||||||
We created a special Træfik command to help configuring your Key Value store from a Træfik TOML configuration file and/or CLI flags.
|
We created a special Traefik command to help configuring your Key Value store from a Traefik TOML configuration file and/or CLI flags.
|
||||||
|
|
||||||
## Deploy a Træfik cluster
|
## Deploy a Traefik cluster
|
||||||
|
|
||||||
The best way we found is to have an initializer service.
|
The best way we found is to have an initializer service.
|
||||||
This service will push the config to Consul via the `storeconfig` sub-command.
|
This service will push the config to Consul via the `storeconfig` sub-command.
|
||||||
|
@ -173,7 +173,7 @@ The initializer in a docker-compose file will be:
|
||||||
- consul
|
- consul
|
||||||
```
|
```
|
||||||
|
|
||||||
And now, the Træfik part will only have the Consul configuration.
|
And now, the Traefik part will only have the Consul configuration.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
traefik:
|
traefik:
|
||||||
|
@ -189,10 +189,10 @@ And now, the Træfik part will only have the Consul configuration.
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
For Træfik <1.5.0 add `acme.storage=traefik/acme/account` because Træfik is not reading it from Consul.
|
For Traefik <1.5.0 add `acme.storage=traefik/acme/account` because Traefik is not reading it from Consul.
|
||||||
|
|
||||||
If you have some update to do, update the initializer service and re-deploy it.
|
If you have some update to do, update the initializer service and re-deploy it.
|
||||||
The new configuration will be stored in Consul, and you need to restart the Træfik node: `docker service update --force traefik_traefik`.
|
The new configuration will be stored in Consul, and you need to restart the Traefik node: `docker service update --force traefik_traefik`.
|
||||||
|
|
||||||
## Full docker-compose file
|
## Full docker-compose file
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Clustering / High Availability (beta)
|
# Clustering / High Availability (beta)
|
||||||
|
|
||||||
This guide explains how to use Træfik in high availability mode.
|
This guide explains how to use Traefik in high availability mode.
|
||||||
|
|
||||||
In order to deploy and configure multiple Træfik instances, without copying the same configuration file on each instance, we will use a distributed Key-Value store.
|
In order to deploy and configure multiple Traefik instances, without copying the same configuration file on each instance, we will use a distributed Key-Value store.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
@ -11,23 +11,23 @@ _(Currently, we recommend [Consul](https://consul.io) .)_
|
||||||
|
|
||||||
## File configuration to KV store migration
|
## File configuration to KV store migration
|
||||||
|
|
||||||
We created a special Træfik command to help configuring your Key Value store from a Træfik TOML configuration file.
|
We created a special Traefik command to help configuring your Key Value store from a Traefik TOML configuration file.
|
||||||
|
|
||||||
Please refer to [this section](/user-guide/kv-config/#store-configuration-in-key-value-store) to get more details.
|
Please refer to [this section](/user-guide/kv-config/#store-configuration-in-key-value-store) to get more details.
|
||||||
|
|
||||||
## Deploy a Træfik cluster
|
## Deploy a Traefik cluster
|
||||||
|
|
||||||
Once your Træfik configuration is uploaded on your KV store, you can start each Træfik instance.
|
Once your Traefik configuration is uploaded on your KV store, you can start each Traefik instance.
|
||||||
|
|
||||||
A Træfik cluster is based on a manager/worker model.
|
A Traefik cluster is based on a manager/worker model.
|
||||||
|
|
||||||
When starting, Træfik will elect a manager.
|
When starting, Traefik will elect a manager.
|
||||||
If this instance fails, another manager will be automatically elected.
|
If this instance fails, another manager will be automatically elected.
|
||||||
|
|
||||||
## Træfik cluster and Let's Encrypt
|
## Traefik cluster and Let's Encrypt
|
||||||
|
|
||||||
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#as-a-key-value-store-entry).**
|
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#as-a-key-value-store-entry).**
|
||||||
|
|
||||||
Thanks to the Træfik cluster mode algorithm (based on [the Raft Consensus Algorithm](https://raft.github.io/)), only one instance will contact Let's encrypt to solve the challenges.
|
Thanks to the Traefik cluster mode algorithm (based on [the Raft Consensus Algorithm](https://raft.github.io/)), only one instance will contact Let's encrypt to solve the challenges.
|
||||||
|
|
||||||
The others instances will get ACME certificate from the KV Store entry.
|
The others instances will get ACME certificate from the KV Store entry.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Let's Encrypt & Docker
|
# Let's Encrypt & Docker
|
||||||
|
|
||||||
In this use case, we want to use Træfik as a _layer-7_ load balancer with SSL termination for a set of micro-services used to run a web application.
|
In this use case, we want to use Traefik as a _layer-7_ load balancer with SSL termination for a set of micro-services used to run a web application.
|
||||||
|
|
||||||
We also want to automatically _discover any services_ on the Docker host and let Træfik reconfigure itself automatically when containers get created (or shut down) so HTTP traffic can be routed accordingly.
|
We also want to automatically _discover any services_ on the Docker host and let Traefik reconfigure itself automatically when containers get created (or shut down) so HTTP traffic can be routed accordingly.
|
||||||
|
|
||||||
In addition, we want to use Let's Encrypt to automatically generate and renew SSL certificates per hostname.
|
In addition, we want to use Let's Encrypt to automatically generate and renew SSL certificates per hostname.
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ In real-life, you'll want to use your own domain and have the DNS configured acc
|
||||||
Docker containers can only communicate with each other over TCP when they share at least one network.
|
Docker containers can only communicate with each other over TCP when they share at least one network.
|
||||||
This makes sense from a topological point of view in the context of networking, since Docker under the hood creates IPTable rules so containers can't reach other containers _unless you'd want to_.
|
This makes sense from a topological point of view in the context of networking, since Docker under the hood creates IPTable rules so containers can't reach other containers _unless you'd want to_.
|
||||||
|
|
||||||
In this example, we're going to use a single network called `web` where all containers that are handling HTTP traffic (including Træfik) will reside in.
|
In this example, we're going to use a single network called `web` where all containers that are handling HTTP traffic (including Traefik) will reside in.
|
||||||
|
|
||||||
On the Docker host, run the following command:
|
On the Docker host, run the following command:
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ On the Docker host, run the following command:
|
||||||
docker network create web
|
docker network create web
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, let's create a directory on the server where we will configure the rest of Træfik:
|
Now, let's create a directory on the server where we will configure the rest of Traefik:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
mkdir -p /opt/traefik
|
mkdir -p /opt/traefik
|
||||||
|
@ -41,7 +41,7 @@ touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.json
|
||||||
touch /opt/traefik/traefik.toml
|
touch /opt/traefik/traefik.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
The `docker-compose.yml` file will provide us with a simple, consistent and more importantly, a deterministic way to create Træfik.
|
The `docker-compose.yml` file will provide us with a simple, consistent and more importantly, a deterministic way to create Traefik.
|
||||||
|
|
||||||
The contents of the file is as follows:
|
The contents of the file is as follows:
|
||||||
|
|
||||||
|
@ -69,12 +69,12 @@ networks:
|
||||||
```
|
```
|
||||||
|
|
||||||
As you can see, we're mounting the `traefik.toml` file as well as the (empty) `acme.json` file in the container.
|
As you can see, we're mounting the `traefik.toml` file as well as the (empty) `acme.json` file in the container.
|
||||||
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Træfik can listen to Docker events and reconfigure its own internal configuration when containers are created (or shut down).
|
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Traefik can listen to Docker events and reconfigure its own internal configuration when containers are created (or shut down).
|
||||||
Also, we're making sure the container is automatically restarted by the Docker engine in case of problems (or: if the server is rebooted).
|
Also, we're making sure the container is automatically restarted by the Docker engine in case of problems (or: if the server is rebooted).
|
||||||
We're publishing the default HTTP ports `80` and `443` on the host, and making sure the container is placed within the `web` network we've created earlier on.
|
We're publishing the default HTTP ports `80` and `443` on the host, and making sure the container is placed within the `web` network we've created earlier on.
|
||||||
Finally, we're giving this container a static name called `traefik`.
|
Finally, we're giving this container a static name called `traefik`.
|
||||||
|
|
||||||
Let's take a look at a simple `traefik.toml` configuration as well before we'll create the Træfik container:
|
Let's take a look at a simple `traefik.toml` configuration as well before we'll create the Traefik container:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
debug = false
|
debug = false
|
||||||
|
@ -111,17 +111,17 @@ entryPoint = "http"
|
||||||
This is the minimum configuration required to do the following:
|
This is the minimum configuration required to do the following:
|
||||||
|
|
||||||
- Log `ERROR`-level messages (or more severe) to the console, but silence `DEBUG`-level messages
|
- Log `ERROR`-level messages (or more severe) to the console, but silence `DEBUG`-level messages
|
||||||
- Check for new versions of Træfik periodically
|
- Check for new versions of Traefik periodically
|
||||||
- Create two entry points, namely an `HTTP` endpoint on port `80`, and an `HTTPS` endpoint on port `443` where all incoming traffic on port `80` will immediately get redirected to `HTTPS`.
|
- Create two entry points, namely an `HTTP` endpoint on port `80`, and an `HTTPS` endpoint on port `443` where all incoming traffic on port `80` will immediately get redirected to `HTTPS`.
|
||||||
- Enable the Docker provider and listen for container events on the Docker unix socket we've mounted earlier. However, **new containers will not be exposed by Træfik by default, we'll get into this in a bit!**
|
- Enable the Docker provider and listen for container events on the Docker unix socket we've mounted earlier. However, **new containers will not be exposed by Traefik by default, we'll get into this in a bit!**
|
||||||
- Enable automatic request and configuration of SSL certificates using Let's Encrypt.
|
- Enable automatic request and configuration of SSL certificates using Let's Encrypt.
|
||||||
These certificates will be stored in the `acme.json` file, which you can back-up yourself and store off-premises.
|
These certificates will be stored in the `acme.json` file, which you can back-up yourself and store off-premises.
|
||||||
|
|
||||||
Alright, let's boot the container. From the `/opt/traefik` directory, run `docker-compose up -d` which will create and start the Træfik container.
|
Alright, let's boot the container. From the `/opt/traefik` directory, run `docker-compose up -d` which will create and start the Traefik container.
|
||||||
|
|
||||||
## Exposing Web Services to the Outside World
|
## Exposing Web Services to the Outside World
|
||||||
|
|
||||||
Now that we've fully configured and started Træfik, it's time to get our applications running!
|
Now that we've fully configured and started Traefik, it's time to get our applications running!
|
||||||
|
|
||||||
Let's take a simple example of a micro-service project consisting of various services, where some will be exposed to the outside world and some will not.
|
Let's take a simple example of a micro-service project consisting of various services, where some will be exposed to the outside world and some will not.
|
||||||
|
|
||||||
|
@ -195,10 +195,10 @@ Since the `traefik` container we've created and started earlier is also attached
|
||||||
|
|
||||||
### Labels
|
### Labels
|
||||||
|
|
||||||
As mentioned earlier, we don't want containers exposed automatically by Træfik.
|
As mentioned earlier, we don't want containers exposed automatically by Traefik.
|
||||||
|
|
||||||
The reason behind this is simple: we want to have control over this process ourselves.
|
The reason behind this is simple: we want to have control over this process ourselves.
|
||||||
Thanks to Docker labels, we can tell Træfik how to create its internal routing configuration.
|
Thanks to Docker labels, we can tell Traefik how to create its internal routing configuration.
|
||||||
|
|
||||||
Let's take a look at the labels themselves for the `app` service, which is a HTTP webservice listing on port 9000:
|
Let's take a look at the labels themselves for the `app` service, which is a HTTP webservice listing on port 9000:
|
||||||
|
|
||||||
|
@ -219,13 +219,13 @@ We use both `container labels` and `service labels`.
|
||||||
|
|
||||||
First, we specify the `backend` name which corresponds to the actual service we're routing **to**.
|
First, we specify the `backend` name which corresponds to the actual service we're routing **to**.
|
||||||
|
|
||||||
We also tell Træfik to use the `web` network to route HTTP traffic to this container.
|
We also tell Traefik to use the `web` network to route HTTP traffic to this container.
|
||||||
With the `traefik.enable` label, we tell Træfik to include this container in its internal configuration.
|
With the `traefik.enable` label, we tell Traefik to include this container in its internal configuration.
|
||||||
|
|
||||||
With the `frontend.rule` label, we tell Træfik that we want to route to this container if the incoming HTTP request contains the `Host` `app.my-awesome-app.org`.
|
With the `frontend.rule` label, we tell Traefik that we want to route to this container if the incoming HTTP request contains the `Host` `app.my-awesome-app.org`.
|
||||||
Essentially, this is the actual rule used for Layer-7 load balancing.
|
Essentially, this is the actual rule used for Layer-7 load balancing.
|
||||||
|
|
||||||
Finally but not unimportantly, we tell Træfik to route **to** port `9000`, since that is the actual TCP/IP port the container actually listens on.
|
Finally but not unimportantly, we tell Traefik to route **to** port `9000`, since that is the actual TCP/IP port the container actually listens on.
|
||||||
|
|
||||||
### Service labels
|
### Service labels
|
||||||
|
|
||||||
|
@ -238,25 +238,25 @@ In the example, two service names are defined : `basic` and `admin`.
|
||||||
They allow creating two frontends and two backends.
|
They allow creating two frontends and two backends.
|
||||||
|
|
||||||
- `basic` has only one `service label` : `traefik.basic.protocol`.
|
- `basic` has only one `service label` : `traefik.basic.protocol`.
|
||||||
Træfik will use values set in `traefik.frontend.rule` and `traefik.port` to create the `basic` frontend and backend.
|
Traefik will use values set in `traefik.frontend.rule` and `traefik.port` to create the `basic` frontend and backend.
|
||||||
The frontend listens to incoming HTTP requests which contain the `Host` `app.my-awesome-app.org` and redirect them in `HTTP` to the port `9000` of the backend.
|
The frontend listens to incoming HTTP requests which contain the `Host` `app.my-awesome-app.org` and redirect them in `HTTP` to the port `9000` of the backend.
|
||||||
- `admin` has all the `services labels` needed to create the `admin` frontend and backend (`traefik.admin.frontend.rule`, `traefik.admin.protocol`, `traefik.admin.port`).
|
- `admin` has all the `services labels` needed to create the `admin` frontend and backend (`traefik.admin.frontend.rule`, `traefik.admin.protocol`, `traefik.admin.port`).
|
||||||
Træfik will create a frontend to listen to incoming HTTP requests which contain the `Host` `admin-app.my-awesome-app.org` and redirect them in `HTTPS` to the port `9443` of the backend.
|
Traefik will create a frontend to listen to incoming HTTP requests which contain the `Host` `admin-app.my-awesome-app.org` and redirect them in `HTTPS` to the port `9443` of the backend.
|
||||||
|
|
||||||
#### Gotchas and tips
|
#### Gotchas and tips
|
||||||
|
|
||||||
- Always specify the correct port where the container expects HTTP traffic using `traefik.port` label.
|
- Always specify the correct port where the container expects HTTP traffic using `traefik.port` label.
|
||||||
If a container exposes multiple ports, Træfik may forward traffic to the wrong port.
|
If a container exposes multiple ports, Traefik may forward traffic to the wrong port.
|
||||||
Even if a container only exposes one port, you should always write configuration defensively and explicitly.
|
Even if a container only exposes one port, you should always write configuration defensively and explicitly.
|
||||||
- Should you choose to enable the `exposedByDefault` flag in the `traefik.toml` configuration, be aware that all containers that are placed in the same network as Træfik will automatically be reachable from the outside world, for everyone and everyone to see.
|
- Should you choose to enable the `exposedByDefault` flag in the `traefik.toml` configuration, be aware that all containers that are placed in the same network as Traefik will automatically be reachable from the outside world, for everyone and everyone to see.
|
||||||
Usually, this is a bad idea.
|
Usually, this is a bad idea.
|
||||||
- With the `traefik.frontend.auth.basic` label, it's possible for Træfik to provide a HTTP basic-auth challenge for the endpoints you provide the label for.
|
- With the `traefik.frontend.auth.basic` label, it's possible for Traefik to provide a HTTP basic-auth challenge for the endpoints you provide the label for.
|
||||||
- Træfik has built-in support to automatically export [Prometheus](https://prometheus.io) metrics
|
- Traefik has built-in support to automatically export [Prometheus](https://prometheus.io) metrics
|
||||||
- Træfik supports websockets out of the box. In the example above, the `events`-service could be a NodeJS-based application which allows clients to connect using websocket protocol.
|
- Traefik supports websockets out of the box. In the example above, the `events`-service could be a NodeJS-based application which allows clients to connect using websocket protocol.
|
||||||
Thanks to the fact that HTTPS in our example is enforced, these websockets are automatically secure as well (WSS)
|
Thanks to the fact that HTTPS in our example is enforced, these websockets are automatically secure as well (WSS)
|
||||||
|
|
||||||
### Final thoughts
|
### Final thoughts
|
||||||
|
|
||||||
Using Træfik as a Layer-7 load balancer in combination with both Docker and Let's Encrypt provides you with an extremely flexible, powerful and self-configuring solution for your projects.
|
Using Traefik as a Layer-7 load balancer in combination with both Docker and Let's Encrypt provides you with an extremely flexible, powerful and self-configuring solution for your projects.
|
||||||
|
|
||||||
With Let's Encrypt, your endpoints are automatically secured with production-ready SSL certificates that are renewed automatically as well.
|
With Let's Encrypt, your endpoints are automatically secured with production-ready SSL certificates that are renewed automatically as well.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
You will find here some configuration examples of Træfik.
|
You will find here some configuration examples of Traefik.
|
||||||
|
|
||||||
## HTTP only
|
## HTTP only
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ entryPoint = "https"
|
||||||
|
|
||||||
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com` with described SANs.
|
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com` with described SANs.
|
||||||
|
|
||||||
Træfik generates these certificates when it starts and it needs to be restart if new domains are added.
|
Traefik generates these certificates when it starts and it needs to be restart if new domains are added.
|
||||||
|
|
||||||
### onHostRule option (with HTTP challenge)
|
### onHostRule option (with HTTP challenge)
|
||||||
|
|
||||||
|
@ -122,9 +122,9 @@ entryPoint = "https"
|
||||||
|
|
||||||
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com`.
|
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com`.
|
||||||
|
|
||||||
Træfik generates these certificates when it starts.
|
Traefik generates these certificates when it starts.
|
||||||
|
|
||||||
If a backend is added with a `onHost` rule, Træfik will automatically generate the Let's Encrypt certificate for the new domain (for frontends wired on the `acme.entryPoint`).
|
If a backend is added with a `onHost` rule, Traefik will automatically generate the Let's Encrypt certificate for the new domain (for frontends wired on the `acme.entryPoint`).
|
||||||
|
|
||||||
### OnDemand option (with HTTP challenge)
|
### OnDemand option (with HTTP challenge)
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ entryPoint = "https"
|
||||||
```
|
```
|
||||||
|
|
||||||
DNS challenge needs environment variables to be executed.
|
DNS challenge needs environment variables to be executed.
|
||||||
These variables have to be set on the machine/container that host Træfik.
|
These variables have to be set on the machine/container that host Traefik.
|
||||||
|
|
||||||
These variables are described [in this section](/configuration/acme/#provider).
|
These variables are described [in this section](/configuration/acme/#provider).
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ entryPoint = "https"
|
||||||
```
|
```
|
||||||
|
|
||||||
DNS challenge needs environment variables to be executed.
|
DNS challenge needs environment variables to be executed.
|
||||||
These variables have to be set on the machine/container that host Træfik.
|
These variables have to be set on the machine/container that host Traefik.
|
||||||
|
|
||||||
These variables are described [in this section](/configuration/acme/#provider).
|
These variables are described [in this section](/configuration/acme/#provider).
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ entryPoint = "https"
|
||||||
entryPoint = "http"
|
entryPoint = "http"
|
||||||
```
|
```
|
||||||
|
|
||||||
Træfik will only try to generate a Let's encrypt certificate (thanks to `HTTP-01` challenge) if the domain cannot be checked by the provided certificates.
|
Traefik will only try to generate a Let's encrypt certificate (thanks to `HTTP-01` challenge) if the domain cannot be checked by the provided certificates.
|
||||||
|
|
||||||
### Cluster mode
|
### Cluster mode
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
This section explains how to use Traefik as reverse proxy for gRPC application.
|
This section explains how to use Traefik as reverse proxy for gRPC application.
|
||||||
|
|
||||||
### Træfik configuration
|
### Traefik configuration
|
||||||
|
|
||||||
At last, we configure our Træfik instance to use both self-signed certificates.
|
At last, we configure our Traefik instance to use both self-signed certificates.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
defaultEntryPoints = ["https"]
|
defaultEntryPoints = ["https"]
|
||||||
|
@ -39,7 +39,7 @@ defaultEntryPoints = ["https"]
|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
We don't need specific configuration to use gRPC in Træfik, we just need to use `h2c` protocol, or use HTTPS communications to have HTTP2 with the backend.
|
We don't need specific configuration to use gRPC in Traefik, we just need to use `h2c` protocol, or use HTTPS communications to have HTTP2 with the backend.
|
||||||
|
|
||||||
## With HTTPS
|
## With HTTPS
|
||||||
|
|
||||||
|
@ -75,9 +75,9 @@ with
|
||||||
Common Name (e.g. server FQDN or YOUR name) []: frontend.local
|
Common Name (e.g. server FQDN or YOUR name) []: frontend.local
|
||||||
```
|
```
|
||||||
|
|
||||||
### Træfik configuration
|
### Traefik configuration
|
||||||
|
|
||||||
At last, we configure our Træfik instance to use both self-signed certificates.
|
At last, we configure our Traefik instance to use both self-signed certificates.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
defaultEntryPoints = ["https"]
|
defaultEntryPoints = ["https"]
|
||||||
|
@ -152,7 +152,7 @@ err := s.Serve(lis)
|
||||||
// ...
|
// ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Next we will modify gRPC Client to use our Træfik self-signed certificate:
|
Next we will modify gRPC Client to use our Traefik self-signed certificate:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// ...
|
// ...
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Kubernetes Ingress Controller
|
# Kubernetes Ingress Controller
|
||||||
|
|
||||||
This guide explains how to use Træfik as an Ingress controller for a Kubernetes cluster.
|
This guide explains how to use Traefik as an Ingress controller for a Kubernetes cluster.
|
||||||
|
|
||||||
If you are not familiar with Ingresses in Kubernetes you might want to read the [Kubernetes user guide](https://kubernetes.io/docs/concepts/services-networking/ingress/)
|
If you are not familiar with Ingresses in Kubernetes you might want to read the [Kubernetes user guide](https://kubernetes.io/docs/concepts/services-networking/ingress/)
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ The config files used in this guide can be found in the [examples directory](htt
|
||||||
|
|
||||||
Kubernetes introduces [Role Based Access Control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) in 1.6+ to allow fine-grained control of Kubernetes resources and API.
|
Kubernetes introduces [Role Based Access Control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) in 1.6+ to allow fine-grained control of Kubernetes resources and API.
|
||||||
|
|
||||||
If your cluster is configured with RBAC, you will need to authorize Træfik to use the Kubernetes API. There are two ways to set up the proper permission: Via namespace-specific RoleBindings or a single, global ClusterRoleBinding.
|
If your cluster is configured with RBAC, you will need to authorize Traefik to use the Kubernetes API. There are two ways to set up the proper permission: Via namespace-specific RoleBindings or a single, global ClusterRoleBinding.
|
||||||
|
|
||||||
RoleBindings per namespace enable to restrict granted permissions to the very namespaces only that Træfik is watching over, thereby following the least-privileges principle. This is the preferred approach if Træfik is not supposed to watch all namespaces, and the set of namespaces does not change dynamically. Otherwise, a single ClusterRoleBinding must be employed.
|
RoleBindings per namespace enable to restrict granted permissions to the very namespaces only that Traefik is watching over, thereby following the least-privileges principle. This is the preferred approach if Traefik is not supposed to watch all namespaces, and the set of namespaces does not change dynamically. Otherwise, a single ClusterRoleBinding must be employed.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
RoleBindings per namespace are available in Træfik 1.5 and later. Please use ClusterRoleBindings for older versions.
|
RoleBindings per namespace are available in Traefik 1.5 and later. Please use ClusterRoleBindings for older versions.
|
||||||
|
|
||||||
For the sake of simplicity, this guide will use a ClusterRoleBinding:
|
For the sake of simplicity, this guide will use a ClusterRoleBinding:
|
||||||
|
|
||||||
|
@ -74,11 +74,11 @@ subjects:
|
||||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml
|
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
For namespaced restrictions, one RoleBinding is required per watched namespace along with a corresponding configuration of Træfik's `kubernetes.namespaces` parameter.
|
For namespaced restrictions, one RoleBinding is required per watched namespace along with a corresponding configuration of Traefik's `kubernetes.namespaces` parameter.
|
||||||
|
|
||||||
## Deploy Træfik using a Deployment or DaemonSet
|
## Deploy Traefik using a Deployment or DaemonSet
|
||||||
|
|
||||||
It is possible to use Træfik with a [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) object,
|
It is possible to use Traefik with a [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) object,
|
||||||
whereas both options have their own pros and cons:
|
whereas both options have their own pros and cons:
|
||||||
|
|
||||||
- The scalability can be much better when using a Deployment, because you will have a Single-Pod-per-Node model when using a DaemonSet, whereas you may need less replicas based on your environment when using a Deployment.
|
- The scalability can be much better when using a Deployment, because you will have a Single-Pod-per-Node model when using a DaemonSet, whereas you may need less replicas based on your environment when using a Deployment.
|
||||||
|
@ -221,7 +221,7 @@ spec:
|
||||||
!!! note
|
!!! note
|
||||||
This will create a Daemonset that uses privileged ports 80/8080 on the host. This may not work on all providers, but illustrates the static (non-NodePort) hostPort binding. The `traefik-ingress-service` can still be used inside the cluster to access the DaemonSet pods.
|
This will create a Daemonset that uses privileged ports 80/8080 on the host. This may not work on all providers, but illustrates the static (non-NodePort) hostPort binding. The `traefik-ingress-service` can still be used inside the cluster to access the DaemonSet pods.
|
||||||
|
|
||||||
To deploy Træfik to your cluster start by submitting one of the YAML files to the cluster with `kubectl`:
|
To deploy Traefik to your cluster start by submitting one of the YAML files to the cluster with `kubectl`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-deployment.yaml
|
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-deployment.yaml
|
||||||
|
@ -257,14 +257,14 @@ traefik-ingress-controller-678226159-eqseo 1/1 Running 0 7m
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see that after submitting the Deployment or DaemonSet to Kubernetes it has launched a Pod, and it is now running.
|
You should see that after submitting the Deployment or DaemonSet to Kubernetes it has launched a Pod, and it is now running.
|
||||||
_It might take a few moments for Kubernetes to pull the Træfik image and start the container._
|
_It might take a few moments for Kubernetes to pull the Traefik image and start the container._
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
You could also check the deployment with the Kubernetes dashboard, run
|
You could also check the deployment with the Kubernetes dashboard, run
|
||||||
`minikube dashboard` to open it in your browser, then choose the `kube-system`
|
`minikube dashboard` to open it in your browser, then choose the `kube-system`
|
||||||
namespace from the menu at the top right of the screen.
|
namespace from the menu at the top right of the screen.
|
||||||
|
|
||||||
You should now be able to access Træfik on port 80 of your Minikube instance when using the DaemonSet:
|
You should now be able to access Traefik on port 80 of your Minikube instance when using the DaemonSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl $(minikube ip)
|
curl $(minikube ip)
|
||||||
|
@ -285,23 +285,23 @@ curl $(minikube ip):<NODEPORT>
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
We expect to see a 404 response here as we haven't yet given Træfik any configuration.
|
We expect to see a 404 response here as we haven't yet given Traefik any configuration.
|
||||||
|
|
||||||
All further examples below assume a DaemonSet installation. Deployment users will need to append the NodePort when constructing requests.
|
All further examples below assume a DaemonSet installation. Deployment users will need to append the NodePort when constructing requests.
|
||||||
|
|
||||||
## Deploy Træfik using Helm Chart
|
## Deploy Traefik using Helm Chart
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
The Helm Chart is maintained by the community, not the Træfik project maintainers.
|
The Helm Chart is maintained by the community, not the Traefik project maintainers.
|
||||||
|
|
||||||
Instead of installing Træfik via Kubernetes object directly, you can also use the Træfik Helm chart.
|
Instead of installing Traefik via Kubernetes object directly, you can also use the Traefik Helm chart.
|
||||||
|
|
||||||
Install the Træfik chart by:
|
Install the Traefik chart by:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
helm install stable/traefik
|
helm install stable/traefik
|
||||||
```
|
```
|
||||||
Install the Træfik chart using a values.yaml file.
|
Install the Traefik chart using a values.yaml file.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
helm install --values values.yaml stable/traefik
|
helm install --values values.yaml stable/traefik
|
||||||
|
@ -320,7 +320,7 @@ For more information, check out [the documentation](https://github.com/kubernete
|
||||||
|
|
||||||
## Submitting an Ingress to the Cluster
|
## Submitting an Ingress to the Cluster
|
||||||
|
|
||||||
Lets start by creating a Service and an Ingress that will expose the [Træfik Web UI](https://github.com/containous/traefik#web-ui).
|
Lets start by creating a Service and an Ingress that will expose the [Traefik Web UI](https://github.com/containous/traefik#web-ui).
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
@ -367,7 +367,7 @@ You can get the IP address of your minikube instance by running `minikube ip`:
|
||||||
echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts
|
echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts
|
||||||
```
|
```
|
||||||
|
|
||||||
We should now be able to visit [traefik-ui.minikube](http://traefik-ui.minikube) in the browser and view the Træfik web UI.
|
We should now be able to visit [traefik-ui.minikube](http://traefik-ui.minikube) in the browser and view the Traefik web UI.
|
||||||
|
|
||||||
### Add a TLS Certificate to the Ingress
|
### Add a TLS Certificate to the Ingress
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ If there are any errors while loading the TLS section of an ingress, the whole i
|
||||||
|
|
||||||
## Basic Authentication
|
## Basic Authentication
|
||||||
|
|
||||||
It's possible to protect access to Træfik through basic authentication. (See the [Kubernetes Ingress](/configuration/backends/kubernetes) configuration page for syntactical details and restrictions.)
|
It's possible to protect access to Traefik through basic authentication. (See the [Kubernetes Ingress](/configuration/backends/kubernetes) configuration page for syntactical details and restrictions.)
|
||||||
|
|
||||||
### Creating the Secret
|
### Creating the Secret
|
||||||
|
|
||||||
|
@ -677,7 +677,7 @@ spec:
|
||||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-ingress.yaml
|
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-ingress.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Now visit the [Træfik dashboard](http://traefik-ui.minikube/) and you should see a frontend for each host.
|
Now visit the [Traefik dashboard](http://traefik-ui.minikube/) and you should see a frontend for each host.
|
||||||
Along with a backend listing for each service with a server set up for each pod.
|
Along with a backend listing for each service with a server set up for each pod.
|
||||||
|
|
||||||
If you edit your `/etc/hosts` again you should be able to access the cheese websites in your browser.
|
If you edit your `/etc/hosts` again you should be able to access the cheese websites in your browser.
|
||||||
|
@ -726,7 +726,7 @@ spec:
|
||||||
[examples/k8s/cheeses-ingress.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheeses-ingress.yaml)
|
[examples/k8s/cheeses-ingress.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheeses-ingress.yaml)
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
We are configuring Træfik to strip the prefix from the url path with the `traefik.frontend.rule.type` annotation so that we can use the containers from the previous example without modification.
|
We are configuring Traefik to strip the prefix from the url path with the `traefik.frontend.rule.type` annotation so that we can use the containers from the previous example without modification.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheeses-ingress.yaml
|
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheeses-ingress.yaml
|
||||||
|
@ -744,7 +744,7 @@ You should now be able to visit the websites in your browser.
|
||||||
|
|
||||||
## Multiple Ingress Definitions for the Same Host (or Host+Path)
|
## Multiple Ingress Definitions for the Same Host (or Host+Path)
|
||||||
|
|
||||||
Træfik will merge multiple Ingress definitions for the same host/path pair into one definition.
|
Traefik will merge multiple Ingress definitions for the same host/path pair into one definition.
|
||||||
|
|
||||||
Let's say the number of cheese services is growing.
|
Let's say the number of cheese services is growing.
|
||||||
It is now time to move the cheese services to a dedicated cheese namespace to simplify the managements of cheese and non-cheese services.
|
It is now time to move the cheese services to a dedicated cheese namespace to simplify the managements of cheese and non-cheese services.
|
||||||
|
@ -771,7 +771,7 @@ spec:
|
||||||
servicePort: http
|
servicePort: http
|
||||||
```
|
```
|
||||||
|
|
||||||
Træfik will now look for cheddar service endpoints (ports on healthy pods) in both the cheese and the default namespace.
|
Traefik will now look for cheddar service endpoints (ports on healthy pods) in both the cheese and the default namespace.
|
||||||
Deploying cheddar into the cheese namespace and afterwards shutting down cheddar in the default namespace is enough to migrate the traffic.
|
Deploying cheddar into the cheese namespace and afterwards shutting down cheddar in the default namespace is enough to migrate the traffic.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
@ -824,12 +824,12 @@ Note that priority values must be quoted to avoid numeric interpretation (which
|
||||||
## Forwarding to ExternalNames
|
## Forwarding to ExternalNames
|
||||||
|
|
||||||
When specifying an [ExternalName](https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors),
|
When specifying an [ExternalName](https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors),
|
||||||
Træfik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
|
Traefik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
|
||||||
This still requires setting up a proper port mapping on the Service from the Ingress port to the (external) Service port.
|
This still requires setting up a proper port mapping on the Service from the Ingress port to the (external) Service port.
|
||||||
|
|
||||||
## Disable passing the Host Header
|
## Disable passing the Host Header
|
||||||
|
|
||||||
By default Træfik will pass the incoming Host header to the upstream resource.
|
By default Traefik will pass the incoming Host header to the upstream resource.
|
||||||
|
|
||||||
However, there are times when you may not want this to be the case. For example, if your service is of the ExternalName type.
|
However, there are times when you may not want this to be the case. For example, if your service is of the ExternalName type.
|
||||||
|
|
||||||
|
@ -889,38 +889,38 @@ If you were to visit `example.com/static` the request would then be passed on to
|
||||||
|
|
||||||
## Partitioning the Ingress object space
|
## Partitioning the Ingress object space
|
||||||
|
|
||||||
By default, Træfik processes every Ingress objects it observes. At times, however, it may be desirable to ignore certain objects. The following sub-sections describe common use cases and how they can be handled with Træfik.
|
By default, Traefik processes every Ingress objects it observes. At times, however, it may be desirable to ignore certain objects. The following sub-sections describe common use cases and how they can be handled with Traefik.
|
||||||
|
|
||||||
### Between Træfik and other Ingress controller implementations
|
### Between Traefik and other Ingress controller implementations
|
||||||
|
|
||||||
Sometimes Træfik runs along other Ingress controller implementations. One such example is when both Træfik and a cloud provider Ingress controller are active.
|
Sometimes Traefik runs along other Ingress controller implementations. One such example is when both Traefik and a cloud provider Ingress controller are active.
|
||||||
|
|
||||||
The `kubernetes.io/ingress.class` annotation can be attached to any Ingress object in order to control whether Træfik should handle it.
|
The `kubernetes.io/ingress.class` annotation can be attached to any Ingress object in order to control whether Traefik should handle it.
|
||||||
|
|
||||||
If the annotation is missing, contains an empty value, or the value `traefik`, then the Træfik controller will take responsibility and process the associated Ingress object.
|
If the annotation is missing, contains an empty value, or the value `traefik`, then the Traefik controller will take responsibility and process the associated Ingress object.
|
||||||
|
|
||||||
It is also possible to set the `ingressClass` option in Træfik to a particular value. Træfik will only process matching Ingress objects.
|
It is also possible to set the `ingressClass` option in Traefik to a particular value. Traefik will only process matching Ingress objects.
|
||||||
For instance, setting the option to `traefik-internal` causes Træfik to process Ingress objects with the same `kubernetes.io/ingress.class` annotation value, ignoring all other objects (including those with a `traefik` value, empty value, and missing annotation).
|
For instance, setting the option to `traefik-internal` causes Traefik to process Ingress objects with the same `kubernetes.io/ingress.class` annotation value, ignoring all other objects (including those with a `traefik` value, empty value, and missing annotation).
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Letting multiple ingress controllers handle the same ingress objects can lead to unintended behavior.
|
Letting multiple ingress controllers handle the same ingress objects can lead to unintended behavior.
|
||||||
It is recommended to prefix all ingressClass values with `traefik` to avoid unintended collisions with other ingress implementations.
|
It is recommended to prefix all ingressClass values with `traefik` to avoid unintended collisions with other ingress implementations.
|
||||||
|
|
||||||
### Between multiple Træfik Deployments
|
### Between multiple Traefik Deployments
|
||||||
|
|
||||||
Sometimes multiple Træfik Deployments are supposed to run concurrently.
|
Sometimes multiple Traefik Deployments are supposed to run concurrently.
|
||||||
For instance, it is conceivable to have one Deployment deal with internal and another one with external traffic.
|
For instance, it is conceivable to have one Deployment deal with internal and another one with external traffic.
|
||||||
|
|
||||||
For such cases, it is advisable to classify Ingress objects through a label and configure the `labelSelector` option per each Træfik Deployment accordingly.
|
For such cases, it is advisable to classify Ingress objects through a label and configure the `labelSelector` option per each Traefik Deployment accordingly.
|
||||||
To stick with the internal/external example above, all Ingress objects meant for internal traffic could receive a `traffic-type: internal` label while objects designated for external traffic receive a `traffic-type: external` label.
|
To stick with the internal/external example above, all Ingress objects meant for internal traffic could receive a `traffic-type: internal` label while objects designated for external traffic receive a `traffic-type: external` label.
|
||||||
The label selectors on the Træfik Deployments would then be `traffic-type=internal` and `traffic-type=external`, respectively.
|
The label selectors on the Traefik Deployments would then be `traffic-type=internal` and `traffic-type=external`, respectively.
|
||||||
|
|
||||||
## Traffic Splitting
|
## Traffic Splitting
|
||||||
|
|
||||||
It is possible to split Ingress traffic in a fine-grained manner between multiple deployments using _service weights_.
|
It is possible to split Ingress traffic in a fine-grained manner between multiple deployments using _service weights_.
|
||||||
|
|
||||||
One canonical use case is canary releases where a deployment representing a newer release is to receive an initially small but ever-increasing fraction of the requests over time.
|
One canonical use case is canary releases where a deployment representing a newer release is to receive an initially small but ever-increasing fraction of the requests over time.
|
||||||
The way this can be done in Træfik is to specify a percentage of requests that should go into each deployment.
|
The way this can be done in Traefik is to specify a percentage of requests that should go into each deployment.
|
||||||
|
|
||||||
For instance, say that an application `my-app` runs in version 1.
|
For instance, say that an application `my-app` runs in version 1.
|
||||||
A newer version 2 is about to be released, but confidence in the robustness and reliability of new version running in production can only be gained gradually.
|
A newer version 2 is about to be released, but confidence in the robustness and reliability of new version running in production can only be gained gradually.
|
||||||
|
@ -953,7 +953,7 @@ spec:
|
||||||
```
|
```
|
||||||
|
|
||||||
Take note of the `traefik.ingress.kubernetes.io/service-weights` annotation: It specifies the distribution of requests among the referenced backend services, `my-app` and `my-app-canary`.
|
Take note of the `traefik.ingress.kubernetes.io/service-weights` annotation: It specifies the distribution of requests among the referenced backend services, `my-app` and `my-app-canary`.
|
||||||
With this definition, Træfik will route 99% of the requests to the pods backed by the `my-app` deployment, and 1% to those backed by `my-app-canary`.
|
With this definition, Traefik will route 99% of the requests to the pods backed by the `my-app` deployment, and 1% to those backed by `my-app-canary`.
|
||||||
Over time, the ratio may slowly shift towards the canary deployment until it is deemed to replace the previous main application, in steps such as 5%/95%, 10%/90%, 50%/50%, and finally 100%/0%.
|
Over time, the ratio may slowly shift towards the canary deployment until it is deemed to replace the previous main application, in steps such as 5%/95%, 10%/90%, 50%/50%, and finally 100%/0%.
|
||||||
|
|
||||||
A few conditions must hold for service weights to be applied correctly:
|
A few conditions must hold for service weights to be applied correctly:
|
||||||
|
@ -1006,7 +1006,7 @@ The examples shown deliberately do not specify any [resource limitations](https:
|
||||||
|
|
||||||
In a production environment, however, it is important to set proper bounds, especially with regards to CPU:
|
In a production environment, however, it is important to set proper bounds, especially with regards to CPU:
|
||||||
|
|
||||||
- too strict and Træfik will be throttled while serving requests (as Kubernetes imposes hard quotas)
|
- too strict and Traefik will be throttled while serving requests (as Kubernetes imposes hard quotas)
|
||||||
- too loose and Træfik may waste resources not available for other containers
|
- too loose and Traefik may waste resources not available for other containers
|
||||||
|
|
||||||
When in doubt, you should measure your resource needs, and adjust requests and limits accordingly.
|
When in doubt, you should measure your resource needs, and adjust requests and limits accordingly.
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
Both [static global configuration](/user-guide/kv-config/#static-configuration-in-key-value-store) and [dynamic](/user-guide/kv-config/#dynamic-configuration-in-key-value-store) configuration can be stored in a Key-value store.
|
Both [static global configuration](/user-guide/kv-config/#static-configuration-in-key-value-store) and [dynamic](/user-guide/kv-config/#dynamic-configuration-in-key-value-store) configuration can be stored in a Key-value store.
|
||||||
|
|
||||||
This section explains how to launch Træfik using a configuration loaded from a Key-value store.
|
This section explains how to launch Traefik using a configuration loaded from a Key-value store.
|
||||||
|
|
||||||
Træfik supports several Key-value stores:
|
Traefik supports several Key-value stores:
|
||||||
|
|
||||||
- [Consul](https://consul.io)
|
- [Consul](https://consul.io)
|
||||||
- [etcd](https://coreos.com/etcd/)
|
- [etcd](https://coreos.com/etcd/)
|
||||||
|
@ -20,11 +20,11 @@ We will see the steps to set it up with an easy example.
|
||||||
|
|
||||||
### docker-compose file for Consul
|
### docker-compose file for Consul
|
||||||
|
|
||||||
The Træfik global configuration will be retrieved from a [Consul](https://consul.io) store.
|
The Traefik global configuration will be retrieved from a [Consul](https://consul.io) store.
|
||||||
|
|
||||||
First we have to launch Consul in a container.
|
First we have to launch Consul in a container.
|
||||||
|
|
||||||
The [docker-compose file](https://docs.docker.com/compose/compose-file/) allows us to launch Consul and four instances of the trivial app [emilevauge/whoamI](https://github.com/emilevauge/whoamI) :
|
The [docker-compose file](https://docs.docker.com/compose/compose-file/) allows us to launch Consul and four instances of the trivial app [containous/whoami](https://github.com/containous/whoami) :
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
consul:
|
consul:
|
||||||
|
@ -42,25 +42,25 @@ consul:
|
||||||
- "8302/udp"
|
- "8302/udp"
|
||||||
|
|
||||||
whoami1:
|
whoami1:
|
||||||
image: emilevauge/whoami
|
image: containous/whoami
|
||||||
|
|
||||||
whoami2:
|
whoami2:
|
||||||
image: emilevauge/whoami
|
image: containous/whoami
|
||||||
|
|
||||||
whoami3:
|
whoami3:
|
||||||
image: emilevauge/whoami
|
image: containous/whoami
|
||||||
|
|
||||||
whoami4:
|
whoami4:
|
||||||
image: emilevauge/whoami
|
image: containous/whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
### Upload the configuration in the Key-value store
|
### Upload the configuration in the Key-value store
|
||||||
|
|
||||||
We should now fill the store with the Træfik global configuration.
|
We should now fill the store with the Traefik global configuration.
|
||||||
To do that, we can send the Key-value pairs via [curl commands](https://www.consul.io/intro/getting-started/kv.html) or via the [Web UI](https://www.consul.io/intro/getting-started/ui.html).
|
To do that, we can send the Key-value pairs via [curl commands](https://www.consul.io/intro/getting-started/kv.html) or via the [Web UI](https://www.consul.io/intro/getting-started/ui.html).
|
||||||
|
|
||||||
Fortunately, Træfik allows automation of this process using the `storeconfig` subcommand.
|
Fortunately, Traefik allows automation of this process using the `storeconfig` subcommand.
|
||||||
Please refer to the [store Træfik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
|
Please refer to the [store Traefik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
|
||||||
|
|
||||||
Here is the toml configuration we would like to store in the Key-value Store :
|
Here is the toml configuration we would like to store in the Key-value Store :
|
||||||
|
|
||||||
|
@ -128,11 +128,11 @@ In case you are setting key values manually:
|
||||||
|
|
||||||
Note that we can either give path to certificate file or directly the file content itself.
|
Note that we can either give path to certificate file or directly the file content itself.
|
||||||
|
|
||||||
### Launch Træfik
|
### Launch Traefik
|
||||||
|
|
||||||
We will now launch Træfik in a container.
|
We will now launch Traefik in a container.
|
||||||
|
|
||||||
We use CLI flags to setup the connection between Træfik and Consul.
|
We use CLI flags to setup the connection between Traefik and Consul.
|
||||||
All the rest of the global configuration is stored in Consul.
|
All the rest of the global configuration is stored in Consul.
|
||||||
|
|
||||||
Here is the [docker-compose file](https://docs.docker.com/compose/compose-file/) :
|
Here is the [docker-compose file](https://docs.docker.com/compose/compose-file/) :
|
||||||
|
@ -156,7 +156,7 @@ This variable must be initialized with the ACL token value.
|
||||||
|
|
||||||
If Traefik is launched into a Docker container, the variable `CONSUL_HTTP_TOKEN` can be initialized with the `-e` Docker option : `-e "CONSUL_HTTP_TOKEN=[consul-acl-token-value]"`
|
If Traefik is launched into a Docker container, the variable `CONSUL_HTTP_TOKEN` can be initialized with the `-e` Docker option : `-e "CONSUL_HTTP_TOKEN=[consul-acl-token-value]"`
|
||||||
|
|
||||||
If a Consul ACL is used to restrict Træfik read/write access, one of the following configurations is needed.
|
If a Consul ACL is used to restrict Traefik read/write access, one of the following configurations is needed.
|
||||||
|
|
||||||
- HCL format :
|
- HCL format :
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ So far, only [Consul](https://consul.io) and [etcd](https://coreos.com/etcd/) su
|
||||||
|
|
||||||
To set it up, we should enable [consul security](https://www.consul.io/docs/internals/security.html) (or [etcd security](https://coreos.com/etcd/docs/latest/security.html)).
|
To set it up, we should enable [consul security](https://www.consul.io/docs/internals/security.html) (or [etcd security](https://coreos.com/etcd/docs/latest/security.html)).
|
||||||
|
|
||||||
Then, we have to provide CA, Cert and Key to Træfik using `consul` flags :
|
Then, we have to provide CA, Cert and Key to Traefik using `consul` flags :
|
||||||
|
|
||||||
- `--consul.tls`
|
- `--consul.tls`
|
||||||
- `--consul.tls.ca=path/to/the/file`
|
- `--consul.tls.ca=path/to/the/file`
|
||||||
|
@ -220,10 +220,10 @@ Remember the command `traefik --help` to display the updated list of flags.
|
||||||
|
|
||||||
## Dynamic configuration in Key-value store
|
## Dynamic configuration in Key-value store
|
||||||
|
|
||||||
Following our example, we will provide backends/frontends rules and HTTPS certificates to Træfik.
|
Following our example, we will provide backends/frontends rules and HTTPS certificates to Traefik.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
This section is independent of the way Træfik got its static configuration.
|
This section is independent of the way Traefik got its static configuration.
|
||||||
It means that the static configuration can either come from the same Key-value store or from any other sources.
|
It means that the static configuration can either come from the same Key-value store or from any other sources.
|
||||||
|
|
||||||
### Key-value storage structure
|
### Key-value storage structure
|
||||||
|
@ -360,17 +360,17 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi
|
||||||
|
|
||||||
### Atomic configuration changes
|
### Atomic configuration changes
|
||||||
|
|
||||||
Træfik can watch the backends/frontends configuration changes and generate its configuration automatically.
|
Traefik can watch the backends/frontends configuration changes and generate its configuration automatically.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Only backends/frontends rules are dynamic, the rest of the Træfik configuration stay static.
|
Only backends/frontends rules are dynamic, the rest of the Traefik configuration stay static.
|
||||||
|
|
||||||
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically.
|
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically.
|
||||||
As a result, it may be possible for Træfik to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag.
|
As a result, it may be possible for Traefik to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag.
|
||||||
To solve this problem, Træfik supports a special key called `/traefik/alias`.
|
To solve this problem, Traefik supports a special key called `/traefik/alias`.
|
||||||
If set, Træfik use the value as an alternative key prefix.
|
If set, Traefik use the value as an alternative key prefix.
|
||||||
|
|
||||||
Given the key structure below, Træfik will use the `http://172.17.0.2:80` as its only backend (frontend keys have been omitted for brevity).
|
Given the key structure below, Traefik will use the `http://172.17.0.2:80` as its only backend (frontend keys have been omitted for brevity).
|
||||||
|
|
||||||
| Key | Value |
|
| Key | Value |
|
||||||
|-------------------------------------------------------------------------|-----------------------------|
|
|-------------------------------------------------------------------------|-----------------------------|
|
||||||
|
@ -407,21 +407,21 @@ Here, we have a 50% balance between the `http://172.17.0.3:80` and the `http://1
|
||||||
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Træfik *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik/alias`.
|
Traefik *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik/alias`.
|
||||||
Further, if the `/traefik/alias` key is set, all other configuration with `/traefik/backends` or `/traefik/frontends` prefix are ignored.
|
Further, if the `/traefik/alias` key is set, all other configuration with `/traefik/backends` or `/traefik/frontends` prefix are ignored.
|
||||||
|
|
||||||
## Store configuration in Key-value store
|
## Store configuration in Key-value store
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Don't forget to [setup the connection between Træfik and Key-value store](/user-guide/kv-config/#launch-trfik).
|
Don't forget to [setup the connection between Traefik and Key-value store](/user-guide/kv-config/#launch-traefik).
|
||||||
|
|
||||||
The static Træfik configuration in a key-value store can be automatically created and updated, using the [`storeconfig` subcommand](/basics/#commands).
|
The static Traefik configuration in a key-value store can be automatically created and updated, using the [`storeconfig` subcommand](/basics/#commands).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
traefik storeconfig [flags] ...
|
traefik storeconfig [flags] ...
|
||||||
```
|
```
|
||||||
This command is here only to automate the [process which upload the configuration into the Key-value store](/user-guide/kv-config/#upload-the-configuration-in-the-key-value-store).
|
This command is here only to automate the [process which upload the configuration into the Key-value store](/user-guide/kv-config/#upload-the-configuration-in-the-key-value-store).
|
||||||
Træfik will not start but the [static configuration](/basics/#static-trfik-configuration) will be uploaded into the Key-value store.
|
Traefik will not start but the [static configuration](/basics/#static-traefik-configuration) will be uploaded into the Key-value store.
|
||||||
|
|
||||||
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
|
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Docker Swarm (mode) cluster
|
# Docker Swarm (mode) cluster
|
||||||
|
|
||||||
This section explains how to create a multi-host docker cluster with swarm mode using [docker-machine](https://docs.docker.com/machine) and how to deploy Træfik on it.
|
This section explains how to create a multi-host docker cluster with swarm mode using [docker-machine](https://docs.docker.com/machine) and how to deploy Traefik on it.
|
||||||
|
|
||||||
The cluster consists of:
|
The cluster consists of:
|
||||||
|
|
||||||
|
@ -66,17 +66,17 @@ ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
|
||||||
fnpj8ozfc85zvahx2r540xfcf * manager Ready Active Leader
|
fnpj8ozfc85zvahx2r540xfcf * manager Ready Active Leader
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, let's create a network for Træfik to use.
|
Finally, let's create a network for Traefik to use.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker-machine ssh manager "docker network create --driver=overlay traefik-net"
|
docker-machine ssh manager "docker network create --driver=overlay traefik-net"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Deploy Træfik
|
## Deploy Traefik
|
||||||
|
|
||||||
Let's deploy Træfik as a docker service in our cluster.
|
Let's deploy Traefik as a docker service in our cluster.
|
||||||
The only requirement for Træfik to work with swarm mode is that it needs to run on a manager node - we are going to use a [constraint](https://docs.docker.com/engine/reference/commandline/service_create/#/specify-service-constraints-constraint) for that.
|
The only requirement for Traefik to work with swarm mode is that it needs to run on a manager node - we are going to use a [constraint](https://docs.docker.com/engine/reference/commandline/service_create/#/specify-service-constraints-constraint) for that.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker-machine ssh manager "docker service create \
|
docker-machine ssh manager "docker service create \
|
||||||
|
@ -98,16 +98,16 @@ Let's explain this command:
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
|
||||||
| `--publish 80:80 --publish 8080:8080` | we publish port `80` and `8080` on the cluster. |
|
| `--publish 80:80 --publish 8080:8080` | we publish port `80` and `8080` on the cluster. |
|
||||||
| `--constraint=node.role==manager` | we ask docker to schedule Træfik on a manager node. |
|
| `--constraint=node.role==manager` | we ask docker to schedule Traefik on a manager node. |
|
||||||
| `--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock` | we bind mount the docker socket where Træfik is scheduled to be able to speak to the daemon. |
|
| `--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock` | we bind mount the docker socket where Traefik is scheduled to be able to speak to the daemon. |
|
||||||
| `--network traefik-net` | we attach the Træfik service (and thus the underlying container) to the `traefik-net` network. |
|
| `--network traefik-net` | we attach the Traefik service (and thus the underlying container) to the `traefik-net` network. |
|
||||||
| `--docker` | enable docker provider, and `--docker.swarmMode` to enable the swarm mode on Træfik. |
|
| `--docker` | enable docker provider, and `--docker.swarmMode` to enable the swarm mode on Traefik. |
|
||||||
| `--api` | activate the webUI on port 8080 |
|
| `--api` | activate the webUI on port 8080 |
|
||||||
|
|
||||||
|
|
||||||
## Deploy your apps
|
## Deploy your apps
|
||||||
|
|
||||||
We can now deploy our app on the cluster, here [whoami](https://github.com/emilevauge/whoami), a simple web server in Go.
|
We can now deploy our app on the cluster, here [whoami](https://github.com/containous/whoami), a simple web server in Go.
|
||||||
We start 2 services, on the `traefik-net` network.
|
We start 2 services, on the `traefik-net` network.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -115,13 +115,13 @@ docker-machine ssh manager "docker service create \
|
||||||
--name whoami0 \
|
--name whoami0 \
|
||||||
--label traefik.port=80 \
|
--label traefik.port=80 \
|
||||||
--network traefik-net \
|
--network traefik-net \
|
||||||
emilevauge/whoami"
|
containous/whoami"
|
||||||
|
|
||||||
docker-machine ssh manager "docker service create \
|
docker-machine ssh manager "docker service create \
|
||||||
--name whoami1 \
|
--name whoami1 \
|
||||||
--label traefik.port=80 \
|
--label traefik.port=80 \
|
||||||
--network traefik-net \
|
--network traefik-net \
|
||||||
emilevauge/whoami"
|
containous/whoami"
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
@ -139,12 +139,12 @@ docker-machine ssh manager "docker service ls"
|
||||||
```
|
```
|
||||||
ID NAME MODE REPLICAS IMAGE PORTS
|
ID NAME MODE REPLICAS IMAGE PORTS
|
||||||
moq3dq4xqv6t traefik replicated 1/1 traefik:latest *:80->80/tcp,*:8080->8080/tcp
|
moq3dq4xqv6t traefik replicated 1/1 traefik:latest *:80->80/tcp,*:8080->8080/tcp
|
||||||
ysil6oto1wim whoami0 replicated 1/1 emilevauge/whoami:latest
|
ysil6oto1wim whoami0 replicated 1/1 containous/whoami:latest
|
||||||
z9re2mnl34k4 whoami1 replicated 1/1 emilevauge/whoami:latest
|
z9re2mnl34k4 whoami1 replicated 1/1 containous/whoami:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Access to your apps through Træfik
|
## Access to your apps through Traefik
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -H Host:whoami0.traefik http://$(docker-machine ip manager)
|
curl -H Host:whoami0.traefik http://$(docker-machine ip manager)
|
||||||
|
@ -186,7 +186,7 @@ X-Forwarded-Server: 77fc29c69fe4
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
As Træfik is published, you can access it from any machine and not only the manager.
|
As Traefik is published, you can access it from any machine and not only the manager.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -H Host:whoami0.traefik http://$(docker-machine ip worker1)
|
curl -H Host:whoami0.traefik http://$(docker-machine ip worker1)
|
||||||
|
@ -242,11 +242,11 @@ docker-machine ssh manager "docker service ls"
|
||||||
```
|
```
|
||||||
ID NAME MODE REPLICAS IMAGE PORTS
|
ID NAME MODE REPLICAS IMAGE PORTS
|
||||||
moq3dq4xqv6t traefik replicated 1/1 traefik:latest *:80->80/tcp,*:8080->8080/tcp
|
moq3dq4xqv6t traefik replicated 1/1 traefik:latest *:80->80/tcp,*:8080->8080/tcp
|
||||||
ysil6oto1wim whoami0 replicated 5/5 emilevauge/whoami:latest
|
ysil6oto1wim whoami0 replicated 5/5 containous/whoami:latest
|
||||||
z9re2mnl34k4 whoami1 replicated 5/5 emilevauge/whoami:latest
|
z9re2mnl34k4 whoami1 replicated 5/5 containous/whoami:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Access to your `whoami0` through Træfik multiple times.
|
## Access to your `whoami0` through Traefik multiple times.
|
||||||
|
|
||||||
Repeat the following command multiple times and note that the Hostname changes each time as Traefik load balances each request against the 5 tasks:
|
Repeat the following command multiple times and note that the Hostname changes each time as Traefik load balances each request against the 5 tasks:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Swarm cluster
|
# Swarm cluster
|
||||||
|
|
||||||
This section explains how to create a multi-host [swarm](https://docs.docker.com/swarm) cluster using [docker-machine](https://docs.docker.com/machine/) and how to deploy Træfik on it.
|
This section explains how to create a multi-host [swarm](https://docs.docker.com/swarm) cluster using [docker-machine](https://docs.docker.com/machine/) and how to deploy Traefik on it.
|
||||||
|
|
||||||
The cluster consists of:
|
The cluster consists of:
|
||||||
|
|
||||||
|
@ -71,9 +71,9 @@ eval $(docker-machine env --swarm mhs-demo0)
|
||||||
docker network create --driver overlay --subnet=10.0.9.0/24 my-net
|
docker network create --driver overlay --subnet=10.0.9.0/24 my-net
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deploy Træfik
|
## Deploy Traefik
|
||||||
|
|
||||||
Deploy Træfik:
|
Deploy Traefik:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker $(docker-machine config mhs-demo0) run \
|
docker $(docker-machine config mhs-demo0) run \
|
||||||
|
@ -112,12 +112,12 @@ Let's explain this command:
|
||||||
|
|
||||||
## Deploy your apps
|
## Deploy your apps
|
||||||
|
|
||||||
We can now deploy our app on the cluster, here [whoami](https://github.com/emilevauge/whoami), a simple web server in GO, on the network `my-net`:
|
We can now deploy our app on the cluster, here [whoami](https://github.com/containous/whoami), a simple web server in GO, on the network `my-net`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
eval $(docker-machine env --swarm mhs-demo0)
|
eval $(docker-machine env --swarm mhs-demo0)
|
||||||
docker run -d --name=whoami0 --net=my-net --env="constraint:node==mhs-demo0" emilevauge/whoami
|
docker run -d --name=whoami0 --net=my-net --env="constraint:node==mhs-demo0" containous/whoami
|
||||||
docker run -d --name=whoami1 --net=my-net --env="constraint:node==mhs-demo1" emilevauge/whoami
|
docker run -d --name=whoami1 --net=my-net --env="constraint:node==mhs-demo1" containous/whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Check that everything is started:
|
Check that everything is started:
|
||||||
|
@ -127,12 +127,12 @@ docker ps
|
||||||
```
|
```
|
||||||
```
|
```
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
ba2c21488299 emilevauge/whoami "/whoamI" 8 seconds ago Up 9 seconds 80/tcp mhs-demo1/whoami1
|
ba2c21488299 containous/whoami "/whoamI" 8 seconds ago Up 9 seconds 80/tcp mhs-demo1/whoami1
|
||||||
8147a7746e7a emilevauge/whoami "/whoamI" 19 seconds ago Up 20 seconds 80/tcp mhs-demo0/whoami0
|
8147a7746e7a containous/whoami "/whoamI" 19 seconds ago Up 20 seconds 80/tcp mhs-demo0/whoami0
|
||||||
8fbc39271b4c traefik "/traefik -l DEBUG -c" 36 seconds ago Up 37 seconds 192.168.99.101:80->80/tcp, 192.168.99.101:8080->8080/tcp mhs-demo0/serene_bhabha
|
8fbc39271b4c traefik "/traefik -l DEBUG -c" 36 seconds ago Up 37 seconds 192.168.99.101:80->80/tcp, 192.168.99.101:8080->8080/tcp mhs-demo0/serene_bhabha
|
||||||
```
|
```
|
||||||
|
|
||||||
## Access to your apps through Træfik
|
## Access to your apps through Traefik
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -H Host:whoami0.traefik http://$(docker-machine ip mhs-demo0)
|
curl -H Host:whoami0.traefik http://$(docker-machine ip mhs-demo0)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
## The Træfik Quickstart (Using Docker)
|
## The Traefik Quickstart (Using Docker)
|
||||||
|
|
||||||
In this quickstart, we'll use [Docker compose](https://docs.docker.com/compose) to create our demo infrastructure.
|
In this quickstart, we'll use [Docker compose](https://docs.docker.com/compose) to create our demo infrastructure.
|
||||||
|
|
||||||
To save some time, you can clone [Træfik's repository](https://github.com/containous/traefik) and use the quickstart files located in the [examples/quickstart](https://github.com/containous/traefik/tree/master/examples/quickstart/) directory.
|
To save some time, you can clone [Traefik's repository](https://github.com/containous/traefik) and use the quickstart files located in the [examples/quickstart](https://github.com/containous/traefik/tree/master/examples/quickstart/) directory.
|
||||||
|
|
||||||
### 1 — Launch Træfik — Tell It to Listen to Docker
|
### 1 — Launch Traefik — Tell It to Listen to Docker
|
||||||
|
|
||||||
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Træfik image:
|
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3'
|
version: '3'
|
||||||
|
@ -14,7 +14,7 @@ version: '3'
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik # The official Traefik docker image
|
image: traefik # The official Traefik docker image
|
||||||
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
|
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
|
||||||
ports:
|
ports:
|
||||||
- "80:80" # The HTTP port
|
- "80:80" # The HTTP port
|
||||||
- "8080:8080" # The Web UI (enabled by --api)
|
- "8080:8080" # The Web UI (enabled by --api)
|
||||||
|
@ -22,7 +22,7 @@ services:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock #So that Traefik can listen to the Docker events
|
- /var/run/docker.sock:/var/run/docker.sock #So that Traefik can listen to the Docker events
|
||||||
```
|
```
|
||||||
|
|
||||||
**That's it. Now you can launch Træfik!**
|
**That's it. Now you can launch Traefik!**
|
||||||
|
|
||||||
Start your `reverse-proxy` with the following command:
|
Start your `reverse-proxy` with the following command:
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ Start your `reverse-proxy` with the following command:
|
||||||
docker-compose up -d reverse-proxy
|
docker-compose up -d reverse-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Træfik's dashboard (we'll go back there once we have launched a service in step 2).
|
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Traefik's dashboard (we'll go back there once we have launched a service in step 2).
|
||||||
|
|
||||||
### 2 — Launch a Service — Træfik Detects It and Creates a Route for You
|
### 2 — Launch a Service — Traefik Detects It and Creates a Route for You
|
||||||
|
|
||||||
Now that we have a Træfik instance up and running, we will deploy new services.
|
Now that we have a Traefik instance up and running, we will deploy new services.
|
||||||
|
|
||||||
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ Start the `whoami` service with the following command:
|
||||||
docker-compose up -d whoami
|
docker-compose up -d whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Træfik has automatically detected the new container and updated its own configuration.
|
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||||
|
|
||||||
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
||||||
|
|
||||||
|
@ -77,9 +77,9 @@ Run more instances of your `whoami` service with the following command:
|
||||||
docker-compose up -d --scale whoami=2
|
docker-compose up -d --scale whoami=2
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Træfik has automatically detected the new instance of the container.
|
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new instance of the container.
|
||||||
|
|
||||||
Finally, see that Træfik load-balances between the two instances of your services by running twice the following command:
|
Finally, see that Traefik load-balances between the two instances of your services by running twice the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||||
|
@ -99,9 +99,9 @@ IP: 172.27.0.4
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4 — Enjoy Træfik's Magic
|
### 4 — Enjoy Traefik's Magic
|
||||||
|
|
||||||
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](https://docs.traefik.io/) and let Træfik work for you!
|
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](https://docs.traefik.io/) and let Traefik work for you!
|
||||||
Whatever your infrastructure is, there is probably [an available Træfik backend](https://docs.traefik.io/#supported-backends) that will do the job.
|
Whatever your infrastructure is, there is probably [an available Traefik backend](https://docs.traefik.io/#supported-backends) that will do the job.
|
||||||
|
|
||||||
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](https://docs.traefik.io/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/).
|
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Traefik's let's encrypt integration](https://docs.traefik.io/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/).
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# The reverse proxy service (Træfik)
|
# The reverse proxy service (Traefik)
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik # The official Traefik docker image
|
image: traefik # The official Traefik docker image
|
||||||
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
|
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
|
||||||
ports:
|
ports:
|
||||||
- "80:80" # The HTTP port
|
- "80:80" # The HTTP port
|
||||||
- "8080:8080" # The Web UI (enabled by --api)
|
- "8080:8080" # The Web UI (enabled by --api)
|
||||||
|
|
|
@ -72,7 +72,7 @@ func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
|
||||||
|
|
||||||
u.Path += b.Path
|
u.Path += b.Path
|
||||||
|
|
||||||
return http.NewRequest(http.MethodGet, u.String(), nil)
|
return http.NewRequest(http.MethodGet, u.String(), http.NoBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function adds additional http headers and hostname to http.request
|
// this function adds additional http headers and hostname to http.request
|
||||||
|
|
|
@ -50,7 +50,6 @@ func (s *AccessLogSuite) TearDownTest(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessLogSuite) TestAccessLog(c *check.C) {
|
func (s *AccessLogSuite) TestAccessLog(c *check.C) {
|
||||||
// Ensure working directory is clean
|
|
||||||
ensureWorkingDirectoryIsClean()
|
ensureWorkingDirectoryIsClean()
|
||||||
|
|
||||||
// Start Traefik
|
// Start Traefik
|
||||||
|
@ -95,7 +94,6 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
||||||
// Ensure working directory is clean
|
|
||||||
ensureWorkingDirectoryIsClean()
|
ensureWorkingDirectoryIsClean()
|
||||||
|
|
||||||
expected := []accessLogValue{
|
expected := []accessLogValue{
|
||||||
|
@ -143,7 +141,6 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessLogSuite) TestAccessLogAuthEntrypoint(c *check.C) {
|
func (s *AccessLogSuite) TestAccessLogAuthEntrypoint(c *check.C) {
|
||||||
// Ensure working directory is clean
|
|
||||||
ensureWorkingDirectoryIsClean()
|
ensureWorkingDirectoryIsClean()
|
||||||
|
|
||||||
expected := []accessLogValue{
|
expected := []accessLogValue{
|
||||||
|
@ -191,7 +188,6 @@ func (s *AccessLogSuite) TestAccessLogAuthEntrypoint(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AccessLogSuite) TestAccessLogAuthEntrypointSuccess(c *check.C) {
|
func (s *AccessLogSuite) TestAccessLogAuthEntrypointSuccess(c *check.C) {
|
||||||
// Ensure working directory is clean
|
|
||||||
ensureWorkingDirectoryIsClean()
|
ensureWorkingDirectoryIsClean()
|
||||||
|
|
||||||
expected := []accessLogValue{
|
expected := []accessLogValue{
|
||||||
|
@ -647,6 +643,54 @@ func (s *AccessLogSuite) TestAccessLogFrontendWhitelist(c *check.C) {
|
||||||
checkNoOtherTraefikProblems(c)
|
checkNoOtherTraefikProblems(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
|
||||||
|
ensureWorkingDirectoryIsClean()
|
||||||
|
|
||||||
|
expected := []accessLogValue{
|
||||||
|
{
|
||||||
|
formatOnly: false,
|
||||||
|
code: "200",
|
||||||
|
user: "test",
|
||||||
|
frontendName: "Host-frontend-auth-docker",
|
||||||
|
backendURL: "http://172.17.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Traefik
|
||||||
|
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
|
||||||
|
defer display(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
checkStatsForLogFile(c)
|
||||||
|
|
||||||
|
s.composeProject.Container(c, "authFrontend")
|
||||||
|
|
||||||
|
waitForTraefik(c, "authFrontend")
|
||||||
|
|
||||||
|
// Verify Traefik started OK
|
||||||
|
checkTraefikStarted(c)
|
||||||
|
|
||||||
|
// Test auth entrypoint
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8006/", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = "frontend.auth.docker.local"
|
||||||
|
req.SetBasicAuth("test", "test")
|
||||||
|
|
||||||
|
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// Verify access.log output as expected
|
||||||
|
count := checkAccessLogExactValuesOutput(c, expected)
|
||||||
|
|
||||||
|
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
|
||||||
|
|
||||||
|
// Verify no other Traefik problems
|
||||||
|
checkNoOtherTraefikProblems(c)
|
||||||
|
}
|
||||||
|
|
||||||
func checkNoOtherTraefikProblems(c *check.C) {
|
func checkNoOtherTraefikProblems(c *check.C) {
|
||||||
traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
|
traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
|
@ -415,3 +415,51 @@ func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestDontKeepTrailingSlash(c *check.C) {
|
||||||
|
file := s.adaptFile(c, "fixtures/keep_trailing_slash.toml", struct {
|
||||||
|
KeepTrailingSlash bool
|
||||||
|
}{false})
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer output(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
oldCheckRedirect := http.DefaultClient.CheckRedirect
|
||||||
|
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/test/foo/", 1*time.Second, try.StatusCodeIs(http.StatusMovedPermanently))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
http.DefaultClient.CheckRedirect = oldCheckRedirect
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestKeepTrailingSlash(c *check.C) {
|
||||||
|
file := s.adaptFile(c, "fixtures/keep_trailing_slash.toml", struct {
|
||||||
|
KeepTrailingSlash bool
|
||||||
|
}{true})
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer output(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
oldCheckRedirect := http.DefaultClient.CheckRedirect
|
||||||
|
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8000/test/foo/", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
http.DefaultClient.CheckRedirect = oldCheckRedirect
|
||||||
|
}
|
||||||
|
|
|
@ -478,7 +478,7 @@ func datastoreContains(datastore *cluster.Datastore, expectedValue string) func(
|
||||||
func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||||
s.setupConsul(c)
|
s.setupConsul(c)
|
||||||
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
|
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
|
||||||
// start Træfik
|
// start Traefik
|
||||||
file := s.adaptFile(c, "fixtures/consul/simple_https.toml", struct{ ConsulHost string }{consulHost})
|
file := s.adaptFile(c, "fixtures/consul/simple_https.toml", struct{ ConsulHost string }{consulHost})
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||||
|
|
|
@ -447,7 +447,7 @@ func (s *Etcd3Suite) TestCommandStoreConfig(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||||
// start Træfik
|
// start Traefik
|
||||||
cmd, display := s.traefikCmd(
|
cmd, display := s.traefikCmd(
|
||||||
withConfigFile("fixtures/etcd/simple_https.toml"),
|
withConfigFile("fixtures/etcd/simple_https.toml"),
|
||||||
"--etcd",
|
"--etcd",
|
||||||
|
@ -584,7 +584,7 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) {
|
func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) {
|
||||||
// start Træfik
|
// start Traefik
|
||||||
cmd, display := s.traefikCmd(
|
cmd, display := s.traefikCmd(
|
||||||
withConfigFile("fixtures/etcd/simple_https.toml"),
|
withConfigFile("fixtures/etcd/simple_https.toml"),
|
||||||
"--etcd",
|
"--etcd",
|
||||||
|
|
31
integration/fixtures/grpc/config_with_flush.toml
Normal file
31
integration/fixtures/grpc/config_with_flush.toml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
defaultEntryPoints = ["https"]
|
||||||
|
|
||||||
|
rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.https]
|
||||||
|
address = ":4443"
|
||||||
|
[entryPoints.https.tls]
|
||||||
|
[[entryPoints.https.tls.certificates]]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
||||||
|
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[file]
|
||||||
|
|
||||||
|
[backends]
|
||||||
|
[backends.backend1]
|
||||||
|
[backends.backend1.responseForwarding]
|
||||||
|
flushInterval="1ms"
|
||||||
|
[backends.backend1.servers.server1]
|
||||||
|
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
|
||||||
|
[frontends]
|
||||||
|
[frontends.frontend1]
|
||||||
|
backend = "backend1"
|
||||||
|
[frontends.frontend1.routes.test_1]
|
||||||
|
rule = "Host:127.0.0.1"
|
|
@ -18,6 +18,21 @@
|
||||||
[frontends.frontend2.routes.test_2]
|
[frontends.frontend2.routes.test_2]
|
||||||
rule = "Host:snitest.org"
|
rule = "Host:snitest.org"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
# bad certificates to validate the loop on the certificate appending
|
||||||
|
[tls.certificate]
|
||||||
|
# bad content
|
||||||
|
certFile = """-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC/zCCAeegAwIBAgIJALAYHG/vGqWEMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
|
||||||
|
-----END CERTIFICATE-----"""
|
||||||
|
# bad content
|
||||||
|
keyFile = """-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
wihZ13e3i5UQEYuoRcH1RUd1wyYoBSKuQnsT2WwVZ1wlXSYaELAbQgaI9NtfBA0G
|
||||||
|
eRG3DaVpez4DQVupZDHMgxJUYqqKynUj6GD1YiaxGROj3TYCu6e7OxyhalhCllSu
|
||||||
|
w/X5M802XqzLjeec5zHoZDfknnAkgR9MsxZYmZPFaDyL6GOKUB8=
|
||||||
|
-----END RSA PRIVATE KEY-----"""
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
entryPoints = ["https"]
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
|
|
20
integration/fixtures/https/wildcard.www.snitest.com.cert
Normal file
20
integration/fixtures/https/wildcard.www.snitest.com.cert
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDMDCCAhgCCQC425NNs+WWZzANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJG
|
||||||
|
UjELMAkGA1UECAwCTFkxDTALBgNVBAcMBEx5b24xEzARBgNVBAoMCkNvbnRhaW5v
|
||||||
|
dXMxGjAYBgNVBAMMESoud3d3LnNuaXRlc3QuY29tMB4XDTE4MTAyMjE0MjcxNFoX
|
||||||
|
DTI4MTAxOTE0MjcxNFowWjELMAkGA1UEBhMCRlIxCzAJBgNVBAgMAkxZMQ0wCwYD
|
||||||
|
VQQHDARMeW9uMRMwEQYDVQQKDApDb250YWlub3VzMRowGAYDVQQDDBEqLnd3dy5z
|
||||||
|
bml0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwFbc/I
|
||||||
|
gpOVNoefnIQrAy2wqK3VKSjFT5z5E8MVrHSU9PpC8bGQb0hTULmfHSzRTsajRLjv
|
||||||
|
rLM/EZDrJL+PQHcCG+XVYbqMmVis4qsevuOyFdFdfe66LIsV+zmsSUbMyssGS2Qw
|
||||||
|
AZx2D8RDtY35VcSA845gjQH+KfF1ST4s/73sr8ID5ZEEn4J6fbmrVfbxhygsx036
|
||||||
|
VNw8OKby+7Gx3irz1ZC6JZ6jmzqlsu4EuDY1cjHCZSUD/JQ1jHz3gIRLV9OiglN/
|
||||||
|
PAPu8zZZ/vtalEGytpLUcbjmvNg24Yc94vd3W3r4Ne13FhDLnB3w8Gz4pYZsEgkk
|
||||||
|
18LzttWcqHnNwg8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAW1XJBk7oCGkzF4nR
|
||||||
|
0l2cEpG2QkHAUuXRa4PqH9QALUj2taAZHGiFF0UsknjbCnTsX6rzSLy1NFiJxyuO
|
||||||
|
CmaiZ9Y9mcYw+T+SXo862Yu1Jch48LoD5x1vW/F8ZT+Fnl+gXoh7ssAtjQ4YViWy
|
||||||
|
Z3A1y54Mb6JhuVjfOBuzbGwI9DDAetKZgTVY7SCm7MTrF5z/YMly5rixV5th1XCj
|
||||||
|
4bqZ9p4CZyP++Y4RffKuCf35cyD/9Y7Boq5A3E8LoxMRFzszyn9RhKdkKLOevGgc
|
||||||
|
r4H/w92uaQqQGRTxQfNWfphBdNuc+ZgXYIGiexcpqxJfA0Ei7XSsKVxxXNxLoJe5
|
||||||
|
3xs+Lg==
|
||||||
|
-----END CERTIFICATE-----
|
28
integration/fixtures/https/wildcard.www.snitest.com.key
Normal file
28
integration/fixtures/https/wildcard.www.snitest.com.key
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDMBW3PyIKTlTaH
|
||||||
|
n5yEKwMtsKit1SkoxU+c+RPDFax0lPT6QvGxkG9IU1C5nx0s0U7Go0S476yzPxGQ
|
||||||
|
6yS/j0B3Ahvl1WG6jJlYrOKrHr7jshXRXX3uuiyLFfs5rElGzMrLBktkMAGcdg/E
|
||||||
|
Q7WN+VXEgPOOYI0B/inxdUk+LP+97K/CA+WRBJ+Cen25q1X28YcoLMdN+lTcPDim
|
||||||
|
8vuxsd4q89WQuiWeo5s6pbLuBLg2NXIxwmUlA/yUNYx894CES1fTooJTfzwD7vM2
|
||||||
|
Wf77WpRBsraS1HG45rzYNuGHPeL3d1t6+DXtdxYQy5wd8PBs+KWGbBIJJNfC87bV
|
||||||
|
nKh5zcIPAgMBAAECggEAW6lEwMmRAMVVDnHDXA4HC4wG/LJ8H3kmX5v4KPmf1XDm
|
||||||
|
71kMRX5iwNfNuNenv+75uXy4722e5Zk8RyOeCwJNMCqeZhAMLEfmzVQ/MipKEPp9
|
||||||
|
muaqIYs7X/GsQSkKcuinY7ecP5Lh5m2Uf9T7yKFwyyw0QI9YSsDqDzVmhqyo6aaT
|
||||||
|
ob4Bua9mTOTMCjEaIk06SkS0Z5sCqtvKMMx/fI2XYSmxQvbwYPHInpyu2LQAvKTw
|
||||||
|
wpwDLF4Zetw1Tutbk8TSTaoC2rn6ZH5DYdJ9pk55/+UqVPo8tu/M//8JN0t9GY1/
|
||||||
|
aqJ25juHjj0pfp+0830NOs4n6symBcR4bSbDn7r/4QKBgQDnTOdo09jtzJimGlbH
|
||||||
|
zEqYOi0NrWU/mLkpqbczjKqx8BnTyfF3FudhY7Gp2v1WX/ofjYS/P/2nY6sXKvig
|
||||||
|
9htqLRCe0Tk9vavY3eSEyaHu9Tbeixx7lM4pQfHCASreMp37RyhIisSPkzdCChNb
|
||||||
|
OuqYpTW4C2u9schMlmCVaWYtTQKBgQDhzsoIlWAAD//h2xqCGpcar0SzgPCHdUH6
|
||||||
|
4ejVhmWPfy5Jlk1CwStlsO4BlcTW7ahN81GqIlyiqpi3O2JZ4HfdoZgKNdMK6YD5
|
||||||
|
TkmXnABa42RrQtYHltvJCthctmjP7qoRxvDrDKLBY481AZjC1MNgPlpSrfALMibx
|
||||||
|
wyd6rjQuywKBgH+nuAfo8866nnz+CGsY2wqNARSNYFXrKjZOTqgKuKKgCwEScUvy
|
||||||
|
vhzH8uP10t/69Ia5ikwrOwlJPsH4m2PqsFK3MHcWrerfZZq5TEflKJRDjdbhHAUw
|
||||||
|
qV+n34/dKRWdBggKy7bNr5I2A8dU3D37lEJO3AkJdJsrJYrva7rKgvP5AoGAXNer
|
||||||
|
VfAk8qGhcfmmYowQSNZ7htqjCu75W+/6zaBerat7GqKDzcii0UL3+QrdTgmVQ8eh
|
||||||
|
cjSCphdCh0QRYiba4fOJEdmjlj7/2oGH3KA1vSj1puxqF+C9KWIeJ7CQU74rivej
|
||||||
|
IuGlIaKPxRmM976HPlEkzg3aPqA2Rv0YhGaP6hUCgYA3hEG6daHOj6/P+rR28wTp
|
||||||
|
xyraym7/8BOVWLweUFVM7YKOKrLAa7lhd254Twy0wUvTgiIw/XamhiVmdSh80gI9
|
||||||
|
hooqYern7WGoL9zU2spVaEe2AzhSRvTuLqlRRyLLnPC6uaGVeC+SYD7zIDB2cwyC
|
||||||
|
bbvXmg15uPp02YpLtm8wyw==
|
||||||
|
-----END PRIVATE KEY-----
|
23
integration/fixtures/keep_trailing_slash.toml
Normal file
23
integration/fixtures/keep_trailing_slash.toml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
|
keepTrailingSlash = {{ .KeepTrailingSlash }}
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.http]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[file]
|
||||||
|
|
||||||
|
# rules
|
||||||
|
[backends]
|
||||||
|
[backends.backend1]
|
||||||
|
[backends.backend1.servers.server1]
|
||||||
|
url = "http://172.17.0.2:80"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
[frontends]
|
||||||
|
[frontends.frontend1]
|
||||||
|
backend = "backend1"
|
||||||
|
[frontends.frontend1.routes.test_1]
|
||||||
|
rule = "Path:/test/foo"
|
|
@ -361,3 +361,64 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
|
||||||
})
|
})
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
|
||||||
|
stopStreamExample := make(chan bool)
|
||||||
|
defer func() { stopStreamExample <- true }()
|
||||||
|
lis, err := net.Listen("tcp", ":0")
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
_, port, err := net.SplitHostPort(lis.Addr().String())
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := startGRPCServer(lis, &myserver{
|
||||||
|
stopStreamExample: stopStreamExample,
|
||||||
|
})
|
||||||
|
c.Log(err)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
file := s.adaptFile(c, "fixtures/grpc/config_with_flush.toml", struct {
|
||||||
|
CertContent string
|
||||||
|
KeyContent string
|
||||||
|
GRPCServerPort string
|
||||||
|
}{
|
||||||
|
CertContent: string(LocalhostCert),
|
||||||
|
KeyContent: string(LocalhostKey),
|
||||||
|
GRPCServerPort: port,
|
||||||
|
})
|
||||||
|
|
||||||
|
defer os.Remove(file)
|
||||||
|
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer display(c)
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
// wait for Traefik
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
var client helloworld.Greeter_StreamExampleClient
|
||||||
|
client, closer, err := callStreamExampleClientGRPC()
|
||||||
|
defer closer()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
received := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
tr, err := client.Recv()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
c.Assert(len(tr.Data), check.Equals, 512)
|
||||||
|
received <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = try.Do(time.Millisecond*100, func() error {
|
||||||
|
select {
|
||||||
|
case <-received:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("failed to receive stream data")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ func (l *LogHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next h
|
||||||
|
|
||||||
next.ServeHTTP(crw, reqWithDataTable)
|
next.ServeHTTP(crw, reqWithDataTable)
|
||||||
|
|
||||||
core[ClientUsername] = usernameIfPresent(reqWithDataTable.URL)
|
core[ClientUsername] = formatUsernameForLog(core[ClientUsername])
|
||||||
|
|
||||||
logDataTable.DownstreamResponse = crw.Header()
|
logDataTable.DownstreamResponse = crw.Header()
|
||||||
|
|
||||||
|
@ -230,14 +230,12 @@ func silentSplitHostPort(value string) (host string, port string) {
|
||||||
return host, port
|
return host, port
|
||||||
}
|
}
|
||||||
|
|
||||||
func usernameIfPresent(theURL *url.URL) string {
|
func formatUsernameForLog(usernameField interface{}) string {
|
||||||
username := "-"
|
username, ok := usernameField.(string)
|
||||||
if theURL.User != nil {
|
if ok && len(username) != 0 {
|
||||||
if name := theURL.User.Username(); name != "" {
|
return username
|
||||||
username = name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return username
|
return "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging handler to log frontend name, backend name, and elapsed time
|
// Logging handler to log frontend name, backend name, and elapsed time
|
||||||
|
|
|
@ -14,10 +14,10 @@ const (
|
||||||
defaultValue = "-"
|
defaultValue = "-"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommonLogFormatter provides formatting in the Træfik common log format
|
// CommonLogFormatter provides formatting in the Traefik common log format
|
||||||
type CommonLogFormatter struct{}
|
type CommonLogFormatter struct{}
|
||||||
|
|
||||||
// Format formats the log entry in the Træfik common log format
|
// Format formats the log entry in the Traefik common log format
|
||||||
func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
b := &bytes.Buffer{}
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
|
|
|
@ -618,7 +618,6 @@ func doLogging(t *testing.T, config *types.AccessLog) {
|
||||||
Method: testMethod,
|
Method: testMethod,
|
||||||
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
|
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
|
||||||
URL: &url.URL{
|
URL: &url.URL{
|
||||||
User: url.UserPassword(testUsername, ""),
|
|
||||||
Path: testPath,
|
Path: testPath,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -641,4 +640,5 @@ func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
|
||||||
logDataTable.Core[RetryAttempts] = testRetryAttempts
|
logDataTable.Core[RetryAttempts] = testRetryAttempts
|
||||||
logDataTable.Core[StartUTC] = testStart.UTC()
|
logDataTable.Core[StartUTC] = testStart.UTC()
|
||||||
logDataTable.Core[StartLocal] = testStart.Local()
|
logDataTable.Core[StartLocal] = testStart.Local()
|
||||||
|
logDataTable.Core[ClientUsername] = testUsername
|
||||||
}
|
}
|
||||||
|
|
60
middlewares/accesslog/save_username.go
Normal file
60
middlewares/accesslog/save_username.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package accesslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/urfave/negroni"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
clientUsernameKey key = "ClientUsername"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SaveUsername sends the Username name to the access logger.
|
||||||
|
type SaveUsername struct {
|
||||||
|
next http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSaveUsername creates a SaveUsername handler.
|
||||||
|
func NewSaveUsername(next http.Handler) http.Handler {
|
||||||
|
return &SaveUsername{next}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *SaveUsername) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
serveSaveUsername(r, func() {
|
||||||
|
sf.next.ServeHTTP(rw, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveNegroniUsername adds the Username to the access logger data table.
|
||||||
|
type SaveNegroniUsername struct {
|
||||||
|
next negroni.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSaveNegroniUsername creates a SaveNegroniUsername handler.
|
||||||
|
func NewSaveNegroniUsername(next negroni.Handler) negroni.Handler {
|
||||||
|
return &SaveNegroniUsername{next}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *SaveNegroniUsername) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
serveSaveUsername(r, func() {
|
||||||
|
sf.next.ServeHTTP(rw, r, next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveSaveUsername(r *http.Request, apply func()) {
|
||||||
|
table := GetLogDataTable(r)
|
||||||
|
|
||||||
|
username, ok := r.Context().Value(clientUsernameKey).(string)
|
||||||
|
if ok {
|
||||||
|
table.Core[ClientUsername] = username
|
||||||
|
}
|
||||||
|
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUserName adds a username to a requests' context
|
||||||
|
func WithUserName(req *http.Request, username string) *http.Request {
|
||||||
|
return req.WithContext(context.WithValue(req.Context(), clientUsernameKey, username))
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
goauth "github.com/abbot/go-http-auth"
|
goauth "github.com/abbot/go-http-auth"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
|
"github.com/containous/traefik/middlewares/accesslog"
|
||||||
"github.com/containous/traefik/middlewares/tracing"
|
"github.com/containous/traefik/middlewares/tracing"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/urfave/negroni"
|
"github.com/urfave/negroni"
|
||||||
|
@ -89,7 +89,10 @@ func createAuthDigestHandler(digestAuth *goauth.DigestAuth, authConfig *types.Au
|
||||||
digestAuth.RequireAuth(w, r)
|
digestAuth.RequireAuth(w, r)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Digest auth succeeded")
|
log.Debugf("Digest auth succeeded")
|
||||||
r.URL.User = url.User(username)
|
|
||||||
|
// set username in request context
|
||||||
|
r = accesslog.WithUserName(r, username)
|
||||||
|
|
||||||
if authConfig.HeaderField != "" {
|
if authConfig.HeaderField != "" {
|
||||||
r.Header[authConfig.HeaderField] = []string{username}
|
r.Header[authConfig.HeaderField] = []string{username}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +111,10 @@ func createAuthBasicHandler(basicAuth *goauth.BasicAuth, authConfig *types.Auth)
|
||||||
basicAuth.RequireAuth(w, r)
|
basicAuth.RequireAuth(w, r)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Basic auth succeeded")
|
log.Debugf("Basic auth succeeded")
|
||||||
r.URL.User = url.User(username)
|
|
||||||
|
// set username in request context
|
||||||
|
r = accesslog.WithUserName(r, username)
|
||||||
|
|
||||||
if authConfig.HeaderField != "" {
|
if authConfig.HeaderField != "" {
|
||||||
r.Header[authConfig.HeaderField] = []string{username}
|
r.Header[authConfig.HeaderField] = []string{username}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forwardReq, err := http.NewRequest(http.MethodGet, config.Address, nil)
|
forwardReq, err := http.NewRequest(http.MethodGet, config.Address, http.NoBody)
|
||||||
tracing.LogRequest(tracing.GetSpan(r), forwardReq)
|
tracing.LogRequest(tracing.GetSpan(r), forwardReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tracing.SetErrorAndDebugLog(r, "Error calling %s. Cause %s", config.Address, err)
|
tracing.SetErrorAndDebugLog(r, "Error calling %s. Cause %s", config.Address, err)
|
||||||
|
|
|
@ -123,7 +123,7 @@ func newRequest(baseURL string) (*http.Request, error) {
|
||||||
return nil, fmt.Errorf("error pages: error when parse URL: %v", err)
|
return nil, fmt.Errorf("error pages: error when parse URL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
req, err := http.NewRequest(http.MethodGet, u.String(), http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error pages: error when create query: %v", err)
|
return nil, fmt.Errorf("error pages: error when create query: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ func (retry *Retry) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
// cf https://github.com/containous/traefik/issues/1008
|
// cf https://github.com/containous/traefik/issues/1008
|
||||||
if retry.attempts > 1 {
|
if retry.attempts > 1 {
|
||||||
body := r.Body
|
body := r.Body
|
||||||
|
if body == nil {
|
||||||
|
body = http.NoBody
|
||||||
|
}
|
||||||
defer body.Close()
|
defer body.Close()
|
||||||
r.Body = ioutil.NopCloser(body)
|
r.Body = ioutil.NopCloser(body)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
site_name: Træfik
|
site_name: Traefik
|
||||||
site_description: Træfik Documentation
|
site_description: Traefik Documentation
|
||||||
site_author: containo.us
|
site_author: containo.us
|
||||||
site_url: https://docs.traefik.io
|
site_url: https://docs.traefik.io
|
||||||
dev_addr: 0.0.0.0:8000
|
dev_addr: 0.0.0.0:8000
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
fmtlog "log"
|
fmtlog "log"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -74,10 +75,12 @@ type Certificate struct {
|
||||||
|
|
||||||
// DNSChallenge contains DNS challenge Configuration
|
// DNSChallenge contains DNS challenge Configuration
|
||||||
type DNSChallenge struct {
|
type DNSChallenge struct {
|
||||||
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS."`
|
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS."`
|
||||||
DelayBeforeCheck parse.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."`
|
DelayBeforeCheck parse.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."`
|
||||||
preCheckTimeout time.Duration
|
Resolvers types.DNSResolvers `description:"Use following DNS servers to resolve the FQDN authority."`
|
||||||
preCheckInterval time.Duration
|
DisablePropagationCheck bool `description:"Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]"`
|
||||||
|
preCheckTimeout time.Duration
|
||||||
|
preCheckInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPChallenge contains HTTP challenge Configuration
|
// HTTPChallenge contains HTTP challenge Configuration
|
||||||
|
@ -252,6 +255,9 @@ func (p *Provider) getClient() (*acme.Client, error) {
|
||||||
if p.DNSChallenge != nil && len(p.DNSChallenge.Provider) > 0 {
|
if p.DNSChallenge != nil && len(p.DNSChallenge.Provider) > 0 {
|
||||||
log.Debugf("Using DNS Challenge provider: %s", p.DNSChallenge.Provider)
|
log.Debugf("Using DNS Challenge provider: %s", p.DNSChallenge.Provider)
|
||||||
|
|
||||||
|
SetRecursiveNameServers(p.DNSChallenge.Resolvers)
|
||||||
|
SetPropagationCheck(p.DNSChallenge.DisablePropagationCheck)
|
||||||
|
|
||||||
err = dnsOverrideDelay(p.DNSChallenge.DelayBeforeCheck)
|
err = dnsOverrideDelay(p.DNSChallenge.DelayBeforeCheck)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -784,3 +790,37 @@ func isDomainAlreadyChecked(domainToCheck string, existentDomains []string) bool
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPropagationCheck to disable the Lego PreCheck.
|
||||||
|
func SetPropagationCheck(disable bool) {
|
||||||
|
if disable {
|
||||||
|
acme.PreCheckDNS = func(_, _ string) (bool, error) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRecursiveNameServers to provide a custom DNS resolver.
|
||||||
|
func SetRecursiveNameServers(dnsResolvers []string) {
|
||||||
|
resolvers := normaliseDNSResolvers(dnsResolvers)
|
||||||
|
if len(resolvers) > 0 {
|
||||||
|
acme.RecursiveNameservers = resolvers
|
||||||
|
log.Infof("Validating FQDN authority with DNS using %+v", resolvers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure all servers have a port number
|
||||||
|
func normaliseDNSResolvers(dnsResolvers []string) []string {
|
||||||
|
var normalisedResolvers []string
|
||||||
|
for _, server := range dnsResolvers {
|
||||||
|
srv := strings.TrimSpace(server)
|
||||||
|
if len(srv) > 0 {
|
||||||
|
if host, port, err := net.SplitHostPort(srv); err != nil {
|
||||||
|
normalisedResolvers = append(normalisedResolvers, net.JoinHostPort(srv, "53"))
|
||||||
|
} else {
|
||||||
|
normalisedResolvers = append(normalisedResolvers, net.JoinHostPort(host, port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalisedResolvers
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ func (p *Provider) buildConfiguration(catalog []catalogUpdate) *types.Configurat
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
"getServer": p.getServer,
|
"getServer": p.getServer,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
|
@ -111,7 +112,7 @@ func (p *Provider) getFrontendRule(service serviceUpdate) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.String()
|
return strings.TrimSuffix(buffer.String(), ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getServer(node *api.ServiceEntry) types.Server {
|
func (p *Provider) getServer(node *api.ServiceEntry) types.Server {
|
||||||
|
|
|
@ -408,6 +408,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackend + "=foobar",
|
label.TraefikBackend + "=foobar",
|
||||||
|
|
||||||
label.TraefikBackendCircuitBreakerExpression + "=NetworkErrorRatio() > 0.5",
|
label.TraefikBackendCircuitBreakerExpression + "=NetworkErrorRatio() > 0.5",
|
||||||
|
label.TraefikBackendResponseForwardingFlushInterval + "=10ms",
|
||||||
label.TraefikBackendHealthCheckPath + "=/health",
|
label.TraefikBackendHealthCheckPath + "=/health",
|
||||||
label.TraefikBackendHealthCheckScheme + "=http",
|
label.TraefikBackendHealthCheckScheme + "=http",
|
||||||
label.TraefikBackendHealthCheckPort + "=880",
|
label.TraefikBackendHealthCheckPort + "=880",
|
||||||
|
@ -680,6 +681,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
@ -1036,6 +1040,7 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
service serviceUpdate
|
service serviceUpdate
|
||||||
|
domain string
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -1044,8 +1049,18 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
ServiceName: "foo",
|
ServiceName: "foo",
|
||||||
Attributes: []string{},
|
Attributes: []string{},
|
||||||
},
|
},
|
||||||
|
domain: "localhost",
|
||||||
expected: "Host:foo.localhost",
|
expected: "Host:foo.localhost",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "When no domain should return default host foo",
|
||||||
|
service: serviceUpdate{
|
||||||
|
ServiceName: "foo",
|
||||||
|
Attributes: []string{},
|
||||||
|
},
|
||||||
|
domain: "",
|
||||||
|
expected: "Host:foo",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "Should return host *.example.com",
|
desc: "Should return host *.example.com",
|
||||||
service: serviceUpdate{
|
service: serviceUpdate{
|
||||||
|
@ -1054,6 +1069,7 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
"traefik.frontend.rule=Host:*.example.com",
|
"traefik.frontend.rule=Host:*.example.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
domain: "localhost",
|
||||||
expected: "Host:*.example.com",
|
expected: "Host:*.example.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1064,6 +1080,7 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
"traefik.frontend.rule=Host:{{.ServiceName}}.example.com",
|
"traefik.frontend.rule=Host:{{.ServiceName}}.example.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
domain: "localhost",
|
||||||
expected: "Host:foo.example.com",
|
expected: "Host:foo.example.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1075,6 +1092,7 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
"contextPath=/bar",
|
"contextPath=/bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
domain: "localhost",
|
||||||
expected: "PathPrefix:/bar",
|
expected: "PathPrefix:/bar",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1085,7 +1103,7 @@ func TestProviderGetFrontendRule(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
p := &Provider{
|
p := &Provider{
|
||||||
Domain: "localhost",
|
Domain: test.domain,
|
||||||
Prefix: "traefik",
|
Prefix: "traefik",
|
||||||
FrontEndRule: "Host:{{.ServiceName}}.{{.Domain}}",
|
FrontEndRule: "Host:{{.ServiceName}}.{{.Domain}}",
|
||||||
frontEndRuleTemplate: template.New("consul catalog frontend rule"),
|
frontEndRuleTemplate: template.New("consul catalog frontend rule"),
|
||||||
|
|
|
@ -33,13 +33,14 @@ func (p *Provider) buildConfiguration(containersInspected []dockerData) *types.C
|
||||||
"getDomain": label.GetFuncString(label.TraefikDomain, p.Domain),
|
"getDomain": label.GetFuncString(label.TraefikDomain, p.Domain),
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getIPAddress": p.getDeprecatedIPAddress, // TODO: Should we expose getIPPort instead?
|
"getIPAddress": p.getDeprecatedIPAddress, // TODO: Should we expose getIPPort instead?
|
||||||
"getServers": p.getServers,
|
"getServers": p.getServers,
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
"getCircuitBreaker": label.GetCircuitBreaker,
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getCircuitBreaker": label.GetCircuitBreaker,
|
||||||
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getBackendName": getBackendName,
|
"getBackendName": getBackendName,
|
||||||
|
@ -186,13 +187,16 @@ func (p *Provider) getFrontendRule(container dockerData, segmentLabels map[strin
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := label.GetStringValue(segmentLabels, label.TraefikDomain, p.Domain)
|
domain := label.GetStringValue(segmentLabels, label.TraefikDomain, p.Domain)
|
||||||
|
if len(domain) > 0 {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
if values, err := label.GetStringMultipleStrict(container.Labels, labelDockerComposeProject, labelDockerComposeService); err == nil {
|
if values, err := label.GetStringMultipleStrict(container.Labels, labelDockerComposeProject, labelDockerComposeService); err == nil {
|
||||||
return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + "." + domain
|
return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + domain
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(domain) > 0 {
|
if len(domain) > 0 {
|
||||||
return "Host:" + getSubDomain(container.ServiceName) + "." + domain
|
return "Host:" + getSubDomain(container.ServiceName) + domain
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -436,6 +436,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackend: "foobar",
|
label.TraefikBackend: "foobar",
|
||||||
|
|
||||||
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
||||||
|
label.TraefikBackendResponseForwardingFlushInterval: "10ms",
|
||||||
label.TraefikBackendHealthCheckScheme: "http",
|
label.TraefikBackendHealthCheckScheme: "http",
|
||||||
label.TraefikBackendHealthCheckPath: "/health",
|
label.TraefikBackendHealthCheckPath: "/health",
|
||||||
label.TraefikBackendHealthCheckPort: "880",
|
label.TraefikBackendHealthCheckPort: "880",
|
||||||
|
@ -674,6 +675,9 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -385,6 +385,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackend: "foobar",
|
label.TraefikBackend: "foobar",
|
||||||
|
|
||||||
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
||||||
|
label.TraefikBackendResponseForwardingFlushInterval: "10ms",
|
||||||
label.TraefikBackendHealthCheckScheme: "http",
|
label.TraefikBackendHealthCheckScheme: "http",
|
||||||
label.TraefikBackendHealthCheckPath: "/health",
|
label.TraefikBackendHealthCheckPath: "/health",
|
||||||
label.TraefikBackendHealthCheckPort: "880",
|
label.TraefikBackendHealthCheckPort: "880",
|
||||||
|
@ -592,6 +593,9 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -123,18 +123,17 @@ func (p *Provider) createClient() (client.APIClient, error) {
|
||||||
// Provide allows the docker provider to provide configurations to traefik
|
// Provide allows the docker provider to provide configurations to traefik
|
||||||
// using the given configuration channel.
|
// using the given configuration channel.
|
||||||
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
|
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
|
||||||
// TODO register this routine in pool, and watch for stop channel
|
pool.GoCtx(func(routineCtx context.Context) {
|
||||||
safe.Go(func() {
|
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
var err error
|
var err error
|
||||||
|
ctx, cancel := context.WithCancel(routineCtx)
|
||||||
|
defer cancel()
|
||||||
dockerClient, err := p.createClient()
|
dockerClient, err := p.createClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to create a client for docker, error: %s", err)
|
log.Errorf("Failed to create a client for docker, error: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
serverVersion, err := dockerClient.ServerVersion(ctx)
|
serverVersion, err := dockerClient.ServerVersion(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to retrieve information of the docker client and server host: %s", err)
|
log.Errorf("Failed to retrieve information of the docker client and server host: %s", err)
|
||||||
|
@ -162,12 +161,11 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
Configuration: configuration,
|
Configuration: configuration,
|
||||||
}
|
}
|
||||||
if p.Watch {
|
if p.Watch {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
if p.SwarmMode {
|
if p.SwarmMode {
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
// TODO: This need to be change. Linked to Swarm events docker/docker#23827
|
// TODO: This need to be change. Linked to Swarm events docker/docker#23827
|
||||||
ticker := time.NewTicker(SwarmDefaultWatchTime)
|
ticker := time.NewTicker(SwarmDefaultWatchTime)
|
||||||
pool.Go(func(stop chan bool) {
|
pool.GoCtx(func(ctx context.Context) {
|
||||||
defer close(errChan)
|
defer close(errChan)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -186,9 +184,8 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-stop:
|
case <-ctx.Done():
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
cancel()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,10 +196,6 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
// channel closed
|
// channel closed
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pool.Go(func(stop chan bool) {
|
|
||||||
<-stop
|
|
||||||
cancel()
|
|
||||||
})
|
|
||||||
f := filters.NewArgs()
|
f := filters.NewArgs()
|
||||||
f.Add("type", "container")
|
f.Add("type", "container")
|
||||||
options := dockertypes.EventsOptions{
|
options := dockertypes.EventsOptions{
|
||||||
|
@ -215,7 +208,6 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to list containers for docker, error %s", err)
|
log.Errorf("Failed to list containers for docker, error %s", err)
|
||||||
// Call cancel to get out of the monitor
|
// Call cancel to get out of the monitor
|
||||||
cancel()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
configuration := p.buildConfiguration(containers)
|
configuration := p.buildConfiguration(containers)
|
||||||
|
@ -240,8 +232,9 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
log.Debug("Provider event stream closed")
|
log.Debug("Provider event stream closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +244,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
notify := func(err error, time time.Duration) {
|
notify := func(err error, time time.Duration) {
|
||||||
log.Errorf("Provider connection error %+v, retrying in %s", err, time)
|
log.Errorf("Provider connection error %+v, retrying in %s", err, time)
|
||||||
}
|
}
|
||||||
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), routineCtx), notify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Cannot connect to docker server %+v", err)
|
log.Errorf("Cannot connect to docker server %+v", err)
|
||||||
}
|
}
|
||||||
|
@ -398,7 +391,7 @@ func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes
|
||||||
if service.Spec.EndpointSpec != nil {
|
if service.Spec.EndpointSpec != nil {
|
||||||
if service.Spec.EndpointSpec.Mode == swarmtypes.ResolutionModeDNSRR {
|
if service.Spec.EndpointSpec.Mode == swarmtypes.ResolutionModeDNSRR {
|
||||||
if isBackendLBSwarm(dData) {
|
if isBackendLBSwarm(dData) {
|
||||||
log.Warnf("Ignored %s endpoint-mode not supported, service name: %s. Fallback to Træfik load balancing", swarmtypes.ResolutionModeDNSRR, service.Spec.Annotations.Name)
|
log.Warnf("Ignored %s endpoint-mode not supported, service name: %s. Fallback to Traefik load balancing", swarmtypes.ResolutionModeDNSRR, service.Spec.Annotations.Name)
|
||||||
}
|
}
|
||||||
} else if service.Spec.EndpointSpec.Mode == swarmtypes.ResolutionModeVIP {
|
} else if service.Spec.EndpointSpec.Mode == swarmtypes.ResolutionModeVIP {
|
||||||
dData.NetworkSettings.Networks = make(map[string]*networkData)
|
dData.NetworkSettings.Networks = make(map[string]*networkData)
|
||||||
|
|
|
@ -21,14 +21,16 @@ import (
|
||||||
func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configuration, error) {
|
func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configuration, error) {
|
||||||
var ecsFuncMap = template.FuncMap{
|
var ecsFuncMap = template.FuncMap{
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getHost": getHost,
|
"getHost": getHost,
|
||||||
"getPort": getPort,
|
"getPort": getPort,
|
||||||
"getCircuitBreaker": label.GetCircuitBreaker,
|
"getCircuitBreaker": label.GetCircuitBreaker,
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
"getServers": getServers,
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
|
|
||||||
|
"getServers": getServers,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"filterFrontends": filterFrontends,
|
"filterFrontends": filterFrontends,
|
||||||
|
@ -141,7 +143,11 @@ func (p *Provider) getFrontendRule(i ecsInstance) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := label.GetStringValue(i.SegmentLabels, label.TraefikDomain, p.Domain)
|
domain := label.GetStringValue(i.SegmentLabels, label.TraefikDomain, p.Domain)
|
||||||
defaultRule := "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + domain
|
if len(domain) > 0 {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRule := "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + domain
|
||||||
|
|
||||||
return label.GetStringValue(i.TraefikLabels, label.TraefikFrontendRule, defaultRule)
|
return label.GetStringValue(i.TraefikLabels, label.TraefikFrontendRule, defaultRule)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
|
@ -101,7 +101,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
|
@ -146,7 +146,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Auth: &types.Auth{
|
Auth: &types.Auth{
|
||||||
|
@ -197,7 +197,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Auth: &types.Auth{
|
Auth: &types.Auth{
|
||||||
|
@ -248,7 +248,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Auth: &types.Auth{
|
Auth: &types.Auth{
|
||||||
|
@ -307,7 +307,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Backend: "backend-instance",
|
Backend: "backend-instance",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-instance": {
|
"route-frontend-instance": {
|
||||||
Rule: "Host:instance.",
|
Rule: "Host:instance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Auth: &types.Auth{
|
Auth: &types.Auth{
|
||||||
|
@ -344,6 +344,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackend: aws.String("foobar"),
|
label.TraefikBackend: aws.String("foobar"),
|
||||||
|
|
||||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||||
|
label.TraefikBackendResponseForwardingFlushInterval: aws.String("10ms"),
|
||||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||||
|
@ -461,6 +462,9 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -7,43 +7,45 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
annotationKubernetesIngressClass = "kubernetes.io/ingress.class"
|
annotationKubernetesIngressClass = "kubernetes.io/ingress.class"
|
||||||
annotationKubernetesAuthRealm = "ingress.kubernetes.io/auth-realm"
|
annotationKubernetesAuthRealm = "ingress.kubernetes.io/auth-realm"
|
||||||
annotationKubernetesAuthType = "ingress.kubernetes.io/auth-type"
|
annotationKubernetesAuthType = "ingress.kubernetes.io/auth-type"
|
||||||
annotationKubernetesAuthSecret = "ingress.kubernetes.io/auth-secret"
|
annotationKubernetesAuthSecret = "ingress.kubernetes.io/auth-secret"
|
||||||
annotationKubernetesAuthHeaderField = "ingress.kubernetes.io/auth-header-field"
|
annotationKubernetesAuthHeaderField = "ingress.kubernetes.io/auth-header-field"
|
||||||
annotationKubernetesAuthForwardResponseHeaders = "ingress.kubernetes.io/auth-response-headers"
|
annotationKubernetesAuthForwardResponseHeaders = "ingress.kubernetes.io/auth-response-headers"
|
||||||
annotationKubernetesAuthRemoveHeader = "ingress.kubernetes.io/auth-remove-header"
|
annotationKubernetesAuthRemoveHeader = "ingress.kubernetes.io/auth-remove-header"
|
||||||
annotationKubernetesAuthForwardURL = "ingress.kubernetes.io/auth-url"
|
annotationKubernetesAuthForwardURL = "ingress.kubernetes.io/auth-url"
|
||||||
annotationKubernetesAuthForwardTrustHeaders = "ingress.kubernetes.io/auth-trust-headers"
|
annotationKubernetesAuthForwardTrustHeaders = "ingress.kubernetes.io/auth-trust-headers"
|
||||||
annotationKubernetesAuthForwardTLSSecret = "ingress.kubernetes.io/auth-tls-secret"
|
annotationKubernetesAuthForwardTLSSecret = "ingress.kubernetes.io/auth-tls-secret"
|
||||||
annotationKubernetesAuthForwardTLSInsecure = "ingress.kubernetes.io/auth-tls-insecure"
|
annotationKubernetesAuthForwardTLSInsecure = "ingress.kubernetes.io/auth-tls-insecure"
|
||||||
annotationKubernetesRewriteTarget = "ingress.kubernetes.io/rewrite-target"
|
annotationKubernetesRewriteTarget = "ingress.kubernetes.io/rewrite-target"
|
||||||
annotationKubernetesWhiteListSourceRange = "ingress.kubernetes.io/whitelist-source-range"
|
annotationKubernetesWhiteListSourceRange = "ingress.kubernetes.io/whitelist-source-range"
|
||||||
annotationKubernetesWhiteListIPStrategy = "ingress.kubernetes.io/whitelist-ipstrategy"
|
annotationKubernetesWhiteListIPStrategy = "ingress.kubernetes.io/whitelist-ipstrategy"
|
||||||
annotationKubernetesWhiteListIPStrategyDepth = "ingress.kubernetes.io/whitelist-ipstrategy-depth"
|
annotationKubernetesWhiteListIPStrategyDepth = "ingress.kubernetes.io/whitelist-ipstrategy-depth"
|
||||||
annotationKubernetesWhiteListIPStrategyExcludedIPs = "ingress.kubernetes.io/whitelist-ipstrategy-excluded-ips"
|
annotationKubernetesWhiteListIPStrategyExcludedIPs = "ingress.kubernetes.io/whitelist-ipstrategy-excluded-ips"
|
||||||
annotationKubernetesPreserveHost = "ingress.kubernetes.io/preserve-host"
|
annotationKubernetesPreserveHost = "ingress.kubernetes.io/preserve-host"
|
||||||
annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert"
|
annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert" // Deprecated
|
||||||
annotationKubernetesFrontendEntryPoints = "ingress.kubernetes.io/frontend-entry-points"
|
annotationKubernetesPassTLSClientCert = "ingress.kubernetes.io/pass-client-tls-cert"
|
||||||
annotationKubernetesPriority = "ingress.kubernetes.io/priority"
|
annotationKubernetesFrontendEntryPoints = "ingress.kubernetes.io/frontend-entry-points"
|
||||||
annotationKubernetesCircuitBreakerExpression = "ingress.kubernetes.io/circuit-breaker-expression"
|
annotationKubernetesPriority = "ingress.kubernetes.io/priority"
|
||||||
annotationKubernetesLoadBalancerMethod = "ingress.kubernetes.io/load-balancer-method"
|
annotationKubernetesCircuitBreakerExpression = "ingress.kubernetes.io/circuit-breaker-expression"
|
||||||
annotationKubernetesAffinity = "ingress.kubernetes.io/affinity"
|
annotationKubernetesLoadBalancerMethod = "ingress.kubernetes.io/load-balancer-method"
|
||||||
annotationKubernetesSessionCookieName = "ingress.kubernetes.io/session-cookie-name"
|
annotationKubernetesAffinity = "ingress.kubernetes.io/affinity"
|
||||||
annotationKubernetesRuleType = "ingress.kubernetes.io/rule-type"
|
annotationKubernetesSessionCookieName = "ingress.kubernetes.io/session-cookie-name"
|
||||||
annotationKubernetesRedirectEntryPoint = "ingress.kubernetes.io/redirect-entry-point"
|
annotationKubernetesRuleType = "ingress.kubernetes.io/rule-type"
|
||||||
annotationKubernetesRedirectPermanent = "ingress.kubernetes.io/redirect-permanent"
|
annotationKubernetesRedirectEntryPoint = "ingress.kubernetes.io/redirect-entry-point"
|
||||||
annotationKubernetesRedirectRegex = "ingress.kubernetes.io/redirect-regex"
|
annotationKubernetesRedirectPermanent = "ingress.kubernetes.io/redirect-permanent"
|
||||||
annotationKubernetesRedirectReplacement = "ingress.kubernetes.io/redirect-replacement"
|
annotationKubernetesRedirectRegex = "ingress.kubernetes.io/redirect-regex"
|
||||||
annotationKubernetesMaxConnAmount = "ingress.kubernetes.io/max-conn-amount"
|
annotationKubernetesRedirectReplacement = "ingress.kubernetes.io/redirect-replacement"
|
||||||
annotationKubernetesMaxConnExtractorFunc = "ingress.kubernetes.io/max-conn-extractor-func"
|
annotationKubernetesMaxConnAmount = "ingress.kubernetes.io/max-conn-amount"
|
||||||
annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit"
|
annotationKubernetesMaxConnExtractorFunc = "ingress.kubernetes.io/max-conn-extractor-func"
|
||||||
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages"
|
annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit"
|
||||||
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering"
|
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages"
|
||||||
annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root"
|
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering"
|
||||||
annotationKubernetesServiceWeights = "ingress.kubernetes.io/service-weights"
|
annotationKubernetesResponseForwardingFlushInterval = "ingress.kubernetes.io/responseforwarding-flushinterval"
|
||||||
annotationKubernetesRequestModifier = "ingress.kubernetes.io/request-modifier"
|
annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root"
|
||||||
|
annotationKubernetesServiceWeights = "ingress.kubernetes.io/service-weights"
|
||||||
|
annotationKubernetesRequestModifier = "ingress.kubernetes.io/request-modifier"
|
||||||
|
|
||||||
annotationKubernetesSSLForceHost = "ingress.kubernetes.io/ssl-force-host"
|
annotationKubernetesSSLForceHost = "ingress.kubernetes.io/ssl-force-host"
|
||||||
annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect"
|
annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect"
|
||||||
|
|
|
@ -93,6 +93,13 @@ func circuitBreaker(exp string) func(*types.Backend) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func responseForwarding(interval string) func(*types.Backend) {
|
||||||
|
return func(b *types.Backend) {
|
||||||
|
b.ResponseForwarding = &types.ResponseForwarding{}
|
||||||
|
b.ResponseForwarding.FlushInterval = interval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func buffering(opts ...func(*types.Buffering)) func(*types.Backend) {
|
func buffering(opts ...func(*types.Buffering)) func(*types.Backend) {
|
||||||
return func(b *types.Backend) {
|
return func(b *types.Backend) {
|
||||||
if b.Buffering == nil {
|
if b.Buffering == nil {
|
||||||
|
@ -398,12 +405,34 @@ func limitPeriod(period time.Duration) func(*types.Rate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
func passTLSCert() func(*types.Frontend) {
|
func passTLSCert() func(*types.Frontend) {
|
||||||
return func(f *types.Frontend) {
|
return func(f *types.Frontend) {
|
||||||
f.PassTLSCert = true
|
f.PassTLSCert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func passTLSClientCert() func(*types.Frontend) {
|
||||||
|
return func(f *types.Frontend) {
|
||||||
|
f.PassTLSClientCert = &types.TLSClientHeaders{
|
||||||
|
PEM: true,
|
||||||
|
Infos: &types.TLSClientCertificateInfos{
|
||||||
|
NotAfter: true,
|
||||||
|
NotBefore: true,
|
||||||
|
Subject: &types.TLSCLientCertificateSubjectInfos{
|
||||||
|
Country: true,
|
||||||
|
Province: true,
|
||||||
|
Locality: true,
|
||||||
|
Organization: true,
|
||||||
|
CommonName: true,
|
||||||
|
SerialNumber: true,
|
||||||
|
},
|
||||||
|
Sans: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func routes(opts ...func(*types.Route) string) func(*types.Frontend) {
|
func routes(opts ...func(*types.Route) string) func(*types.Frontend) {
|
||||||
return func(f *types.Frontend) {
|
return func(f *types.Frontend) {
|
||||||
f.Routes = make(map[string]types.Route)
|
f.Routes = make(map[string]types.Route)
|
||||||
|
|
|
@ -43,6 +43,7 @@ const (
|
||||||
traefikDefaultIngressClass = "traefik"
|
traefikDefaultIngressClass = "traefik"
|
||||||
defaultBackendName = "global-default-backend"
|
defaultBackendName = "global-default-backend"
|
||||||
defaultFrontendName = "global-default-frontend"
|
defaultFrontendName = "global-default-frontend"
|
||||||
|
defaultFrontendRule = "PathPrefix:/"
|
||||||
allowedProtocolHTTPS = "https"
|
allowedProtocolHTTPS = "https"
|
||||||
allowedProtocolH2C = "h2c"
|
allowedProtocolH2C = "h2c"
|
||||||
)
|
)
|
||||||
|
@ -61,7 +62,7 @@ type Provider struct {
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
||||||
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
||||||
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"`
|
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"` // Deprecated
|
||||||
Namespaces Namespaces `description:"Kubernetes namespaces" export:"true"`
|
Namespaces Namespaces `description:"Kubernetes namespaces" export:"true"`
|
||||||
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
|
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
|
||||||
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
||||||
|
@ -238,6 +239,11 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseName := r.Host + pa.Path
|
baseName := r.Host + pa.Path
|
||||||
|
|
||||||
|
if len(baseName) == 0 {
|
||||||
|
baseName = pa.Backend.ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
if priority > 0 {
|
if priority > 0 {
|
||||||
baseName = strconv.Itoa(priority) + "-" + baseName
|
baseName = strconv.Itoa(priority) + "-" + baseName
|
||||||
}
|
}
|
||||||
|
@ -269,22 +275,23 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
||||||
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
|
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert) // Deprecated
|
||||||
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
||||||
|
|
||||||
frontend = &types.Frontend{
|
frontend = &types.Frontend{
|
||||||
Backend: baseName,
|
Backend: baseName,
|
||||||
PassHostHeader: passHostHeader,
|
PassHostHeader: passHostHeader,
|
||||||
PassTLSCert: passTLSCert,
|
PassTLSCert: passTLSCert,
|
||||||
Routes: make(map[string]types.Route),
|
PassTLSClientCert: getPassTLSClientCert(i),
|
||||||
Priority: priority,
|
Routes: make(map[string]types.Route),
|
||||||
WhiteList: getWhiteList(i),
|
Priority: priority,
|
||||||
Redirect: getFrontendRedirect(i, baseName, pa.Path),
|
WhiteList: getWhiteList(i),
|
||||||
EntryPoints: entryPoints,
|
Redirect: getFrontendRedirect(i, baseName, pa.Path),
|
||||||
Headers: getHeader(i),
|
EntryPoints: entryPoints,
|
||||||
Errors: getErrorPages(i),
|
Headers: getHeader(i),
|
||||||
RateLimit: getRateLimit(i),
|
Errors: getErrorPages(i),
|
||||||
Auth: auth,
|
RateLimit: getRateLimit(i),
|
||||||
|
Auth: auth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,11 +326,18 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(frontend.Routes) == 0 {
|
||||||
|
frontend.Routes["/"] = types.Route{
|
||||||
|
Rule: defaultFrontendRule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
templateObjects.Frontends[baseName] = frontend
|
templateObjects.Frontends[baseName] = frontend
|
||||||
templateObjects.Backends[baseName].CircuitBreaker = getCircuitBreaker(service)
|
templateObjects.Backends[baseName].CircuitBreaker = getCircuitBreaker(service)
|
||||||
templateObjects.Backends[baseName].LoadBalancer = getLoadBalancer(service)
|
templateObjects.Backends[baseName].LoadBalancer = getLoadBalancer(service)
|
||||||
templateObjects.Backends[baseName].MaxConn = getMaxConn(service)
|
templateObjects.Backends[baseName].MaxConn = getMaxConn(service)
|
||||||
templateObjects.Backends[baseName].Buffering = getBuffering(service)
|
templateObjects.Backends[baseName].Buffering = getBuffering(service)
|
||||||
|
templateObjects.Backends[baseName].ResponseForwarding = getResponseForwarding(service)
|
||||||
|
|
||||||
protocol := label.DefaultProtocol
|
protocol := label.DefaultProtocol
|
||||||
|
|
||||||
|
@ -481,6 +495,7 @@ func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, tem
|
||||||
templateObjects.Backends[defaultBackendName].LoadBalancer = getLoadBalancer(service)
|
templateObjects.Backends[defaultBackendName].LoadBalancer = getLoadBalancer(service)
|
||||||
templateObjects.Backends[defaultBackendName].MaxConn = getMaxConn(service)
|
templateObjects.Backends[defaultBackendName].MaxConn = getMaxConn(service)
|
||||||
templateObjects.Backends[defaultBackendName].Buffering = getBuffering(service)
|
templateObjects.Backends[defaultBackendName].Buffering = getBuffering(service)
|
||||||
|
templateObjects.Backends[defaultBackendName].ResponseForwarding = getResponseForwarding(service)
|
||||||
|
|
||||||
endpoints, exists, err := cl.GetEndpoints(service.Namespace, service.Name)
|
endpoints, exists, err := cl.GetEndpoints(service.Namespace, service.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -520,26 +535,27 @@ func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, tem
|
||||||
}
|
}
|
||||||
|
|
||||||
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
||||||
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
|
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert) // Deprecated
|
||||||
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
|
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
|
||||||
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
||||||
|
|
||||||
templateObjects.Frontends[defaultFrontendName] = &types.Frontend{
|
templateObjects.Frontends[defaultFrontendName] = &types.Frontend{
|
||||||
Backend: defaultBackendName,
|
Backend: defaultBackendName,
|
||||||
PassHostHeader: passHostHeader,
|
PassHostHeader: passHostHeader,
|
||||||
PassTLSCert: passTLSCert,
|
PassTLSCert: passTLSCert,
|
||||||
Routes: make(map[string]types.Route),
|
PassTLSClientCert: getPassTLSClientCert(i),
|
||||||
Priority: priority,
|
Routes: make(map[string]types.Route),
|
||||||
WhiteList: getWhiteList(i),
|
Priority: priority,
|
||||||
Redirect: getFrontendRedirect(i, defaultFrontendName, "/"),
|
WhiteList: getWhiteList(i),
|
||||||
EntryPoints: entryPoints,
|
Redirect: getFrontendRedirect(i, defaultFrontendName, "/"),
|
||||||
Headers: getHeader(i),
|
EntryPoints: entryPoints,
|
||||||
Errors: getErrorPages(i),
|
Headers: getHeader(i),
|
||||||
RateLimit: getRateLimit(i),
|
Errors: getErrorPages(i),
|
||||||
|
RateLimit: getRateLimit(i),
|
||||||
}
|
}
|
||||||
|
|
||||||
templateObjects.Frontends[defaultFrontendName].Routes["/"] = types.Route{
|
templateObjects.Frontends[defaultFrontendName].Routes["/"] = types.Route{
|
||||||
Rule: "PathPrefix:/",
|
Rule: defaultFrontendRule,
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -578,6 +594,7 @@ func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.I
|
||||||
|
|
||||||
rules = append(rules, rule)
|
rules = append(rules, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(rules, ";"), nil
|
return strings.Join(rules, ";"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,6 +968,17 @@ func getIPStrategy(annotations map[string]string) *types.IPStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getResponseForwarding(service *corev1.Service) *types.ResponseForwarding {
|
||||||
|
flushIntervalValue := getStringValue(service.Annotations, annotationKubernetesResponseForwardingFlushInterval, "")
|
||||||
|
if len(flushIntervalValue) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ResponseForwarding{
|
||||||
|
FlushInterval: flushIntervalValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getBuffering(service *corev1.Service) *types.Buffering {
|
func getBuffering(service *corev1.Service) *types.Buffering {
|
||||||
var buffering *types.Buffering
|
var buffering *types.Buffering
|
||||||
|
|
||||||
|
@ -1081,6 +1109,22 @@ func getRateLimit(i *extensionsv1beta1.Ingress) *types.RateLimit {
|
||||||
return rateLimit
|
return rateLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPassTLSClientCert(i *extensionsv1beta1.Ingress) *types.TLSClientHeaders {
|
||||||
|
var passTLSClientCert *types.TLSClientHeaders
|
||||||
|
|
||||||
|
passRaw := getStringValue(i.Annotations, annotationKubernetesPassTLSClientCert, "")
|
||||||
|
if len(passRaw) > 0 {
|
||||||
|
passTLSClientCert = &types.TLSClientHeaders{}
|
||||||
|
err := yaml.Unmarshal([]byte(passRaw), passTLSClientCert)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passTLSClientCert
|
||||||
|
}
|
||||||
|
|
||||||
func templateSafeString(value string) error {
|
func templateSafeString(value string) error {
|
||||||
_, err := strconv.Unquote(`"` + value + `"`)
|
_, err := strconv.Unquote(`"` + value + `"`)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -49,6 +49,11 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
onePath(iBackend("service7", intstr.FromInt(80))),
|
onePath(iBackend("service7", intstr.FromInt(80))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
iRule(iHost(""),
|
||||||
|
iPaths(
|
||||||
|
onePath(iBackend("service8", intstr.FromInt(80))),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -117,6 +122,14 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
clusterIP("10.0.0.7"),
|
clusterIP("10.0.0.7"),
|
||||||
sPorts(sPort(80, ""))),
|
sPorts(sPort(80, ""))),
|
||||||
),
|
),
|
||||||
|
buildService(
|
||||||
|
sName("service8"),
|
||||||
|
sNamespace("testing"),
|
||||||
|
sUID("8"),
|
||||||
|
sSpec(
|
||||||
|
clusterIP("10.0.0.8"),
|
||||||
|
sPorts(sPort(80, ""))),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints := []*corev1.Endpoints{
|
endpoints := []*corev1.Endpoints{
|
||||||
|
@ -164,6 +177,14 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
eAddresses(eAddress("10.10.0.7")),
|
eAddresses(eAddress("10.10.0.7")),
|
||||||
ePorts(ePort(80, ""))),
|
ePorts(ePort(80, ""))),
|
||||||
),
|
),
|
||||||
|
buildEndpoint(
|
||||||
|
eNamespace("testing"),
|
||||||
|
eName("service8"),
|
||||||
|
eUID("8"),
|
||||||
|
subset(
|
||||||
|
eAddresses(eAddress("10.10.0.8")),
|
||||||
|
ePorts(ePort(80, ""))),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
watchChan := make(chan interface{})
|
watchChan := make(chan interface{})
|
||||||
|
@ -217,6 +238,12 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
server("http://10.10.0.7:80", weight(1)),
|
server("http://10.10.0.7:80", weight(1)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
backend("service8",
|
||||||
|
lbMethod("wrr"),
|
||||||
|
servers(
|
||||||
|
server("http://10.10.0.8:80", weight(1)),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
frontends(
|
frontends(
|
||||||
frontend("foo/bar",
|
frontend("foo/bar",
|
||||||
|
@ -247,6 +274,10 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
passHostHeader(),
|
passHostHeader(),
|
||||||
routes(route("*.service7", "HostRegexp:{subdomain:[A-Za-z0-9-_]+}.service7")),
|
routes(route("*.service7", "HostRegexp:{subdomain:[A-Za-z0-9-_]+}.service7")),
|
||||||
),
|
),
|
||||||
|
frontend("service8",
|
||||||
|
passHostHeader(),
|
||||||
|
routes(route("/", "PathPrefix:/")),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
|
@ -696,6 +727,7 @@ func TestGetPassHostHeader(t *testing.T) {
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
func TestGetPassTLSCert(t *testing.T) {
|
func TestGetPassTLSCert(t *testing.T) {
|
||||||
ingresses := []*extensionsv1beta1.Ingress{
|
ingresses := []*extensionsv1beta1.Ingress{
|
||||||
buildIngress(iNamespace("awesome"),
|
buildIngress(iNamespace("awesome"),
|
||||||
|
@ -875,6 +907,9 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
iRule(
|
iRule(
|
||||||
iHost("max-conn"),
|
iHost("max-conn"),
|
||||||
iPaths(onePath(iBackend("service4", intstr.FromInt(804))))),
|
iPaths(onePath(iBackend("service4", intstr.FromInt(804))))),
|
||||||
|
iRule(
|
||||||
|
iHost("flush"),
|
||||||
|
iPaths(onePath(iBackend("service5", intstr.FromInt(805))))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -924,6 +959,15 @@ retryexpression: IsNetworkError() && Attempts() <= 2
|
||||||
clusterIP("10.0.0.4"),
|
clusterIP("10.0.0.4"),
|
||||||
sPorts(sPort(804, "http"))),
|
sPorts(sPort(804, "http"))),
|
||||||
),
|
),
|
||||||
|
buildService(
|
||||||
|
sName("service5"),
|
||||||
|
sNamespace("testing"),
|
||||||
|
sUID("5"),
|
||||||
|
sAnnotation(annotationKubernetesResponseForwardingFlushInterval, "10ms"),
|
||||||
|
sSpec(
|
||||||
|
clusterIP("10.0.0.5"),
|
||||||
|
sPorts(sPort(80, ""))),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints := []*corev1.Endpoints{
|
endpoints := []*corev1.Endpoints{
|
||||||
|
@ -971,6 +1015,17 @@ retryexpression: IsNetworkError() && Attempts() <= 2
|
||||||
eAddresses(eAddress("10.4.0.2")),
|
eAddresses(eAddress("10.4.0.2")),
|
||||||
ePorts(ePort(8080, "http"))),
|
ePorts(ePort(8080, "http"))),
|
||||||
),
|
),
|
||||||
|
buildEndpoint(
|
||||||
|
eNamespace("testing"),
|
||||||
|
eName("service5"),
|
||||||
|
eUID("5"),
|
||||||
|
subset(
|
||||||
|
eAddresses(eAddress("10.4.0.1")),
|
||||||
|
ePorts(ePort(8080, "http"))),
|
||||||
|
subset(
|
||||||
|
eAddresses(eAddress("10.4.0.2")),
|
||||||
|
ePorts(ePort(8080, "http"))),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
watchChan := make(chan interface{})
|
watchChan := make(chan interface{})
|
||||||
|
@ -994,6 +1049,11 @@ retryexpression: IsNetworkError() && Attempts() <= 2
|
||||||
lbMethod("drr"),
|
lbMethod("drr"),
|
||||||
circuitBreaker("NetworkErrorRatio() > 0.5"),
|
circuitBreaker("NetworkErrorRatio() > 0.5"),
|
||||||
),
|
),
|
||||||
|
backend("flush",
|
||||||
|
servers(),
|
||||||
|
lbMethod("wrr"),
|
||||||
|
responseForwarding("10ms"),
|
||||||
|
),
|
||||||
backend("bar",
|
backend("bar",
|
||||||
servers(
|
servers(
|
||||||
server("http://10.15.0.1:8080", weight(1)),
|
server("http://10.15.0.1:8080", weight(1)),
|
||||||
|
@ -1039,6 +1099,10 @@ retryexpression: IsNetworkError() && Attempts() <= 2
|
||||||
passHostHeader(),
|
passHostHeader(),
|
||||||
routes(
|
routes(
|
||||||
route("max-conn", "Host:max-conn"))),
|
route("max-conn", "Host:max-conn"))),
|
||||||
|
frontend("flush",
|
||||||
|
passHostHeader(),
|
||||||
|
routes(
|
||||||
|
route("flush", "Host:flush"))),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1069,6 +1133,20 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
buildIngress(
|
buildIngress(
|
||||||
iNamespace("testing"),
|
iNamespace("testing"),
|
||||||
iAnnotation(annotationKubernetesPassTLSCert, "true"),
|
iAnnotation(annotationKubernetesPassTLSCert, "true"),
|
||||||
|
iAnnotation(annotationKubernetesPassTLSClientCert, `
|
||||||
|
pem: true
|
||||||
|
infos:
|
||||||
|
notafter: true
|
||||||
|
notbefore: true
|
||||||
|
sans: true
|
||||||
|
subject:
|
||||||
|
country: true
|
||||||
|
province: true
|
||||||
|
locality: true
|
||||||
|
organization: true
|
||||||
|
commonname: true
|
||||||
|
serialnumber: true
|
||||||
|
`),
|
||||||
iAnnotation(annotationKubernetesIngressClass, traefikDefaultRealm),
|
iAnnotation(annotationKubernetesIngressClass, traefikDefaultRealm),
|
||||||
iRules(
|
iRules(
|
||||||
iRule(
|
iRule(
|
||||||
|
@ -1484,13 +1562,7 @@ rateset:
|
||||||
),
|
),
|
||||||
frontend("other/sslstuff",
|
frontend("other/sslstuff",
|
||||||
passHostHeader(),
|
passHostHeader(),
|
||||||
passTLSCert(),
|
passTLSClientCert(),
|
||||||
routes(
|
|
||||||
route("/sslstuff", "PathPrefix:/sslstuff"),
|
|
||||||
route("other", "Host:other")),
|
|
||||||
),
|
|
||||||
frontend("other/sslstuff",
|
|
||||||
passHostHeader(),
|
|
||||||
passTLSCert(),
|
passTLSCert(),
|
||||||
routes(
|
routes(
|
||||||
route("/sslstuff", "PathPrefix:/sslstuff"),
|
route("/sslstuff", "PathPrefix:/sslstuff"),
|
||||||
|
|
|
@ -3,6 +3,7 @@ package kv
|
||||||
const (
|
const (
|
||||||
pathBackends = "/backends/"
|
pathBackends = "/backends/"
|
||||||
pathBackendCircuitBreakerExpression = "/circuitbreaker/expression"
|
pathBackendCircuitBreakerExpression = "/circuitbreaker/expression"
|
||||||
|
pathBackendResponseForwardingFlushInterval = "/responseforwarding/flushinterval"
|
||||||
pathBackendHealthCheckScheme = "/healthcheck/scheme"
|
pathBackendHealthCheckScheme = "/healthcheck/scheme"
|
||||||
pathBackendHealthCheckPath = "/healthcheck/path"
|
pathBackendHealthCheckPath = "/healthcheck/path"
|
||||||
pathBackendHealthCheckPort = "/healthcheck/port"
|
pathBackendHealthCheckPort = "/healthcheck/port"
|
||||||
|
|
|
@ -56,12 +56,13 @@ func (p *Provider) buildConfiguration() *types.Configuration {
|
||||||
"getWhiteList": p.getWhiteList,
|
"getWhiteList": p.getWhiteList,
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getServers": p.getServers,
|
"getServers": p.getServers,
|
||||||
"getCircuitBreaker": p.getCircuitBreaker,
|
"getCircuitBreaker": p.getCircuitBreaker,
|
||||||
"getLoadBalancer": p.getLoadBalancer,
|
"getResponseForwarding": p.getResponseForwarding,
|
||||||
"getMaxConn": p.getMaxConn,
|
"getLoadBalancer": p.getLoadBalancer,
|
||||||
"getHealthCheck": p.getHealthCheck,
|
"getMaxConn": p.getMaxConn,
|
||||||
"getBuffering": p.getBuffering,
|
"getHealthCheck": p.getHealthCheck,
|
||||||
|
"getBuffering": p.getBuffering,
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
|
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
|
||||||
|
@ -234,6 +235,20 @@ func (p *Provider) getLoadBalancer(rootPath string) *types.LoadBalancer {
|
||||||
return lb
|
return lb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getResponseForwarding(rootPath string) *types.ResponseForwarding {
|
||||||
|
if !p.has(rootPath, pathBackendResponseForwardingFlushInterval) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value := p.get("", rootPath, pathBackendResponseForwardingFlushInterval)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ResponseForwarding{
|
||||||
|
FlushInterval: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) getCircuitBreaker(rootPath string) *types.CircuitBreaker {
|
func (p *Provider) getCircuitBreaker(rootPath string) *types.CircuitBreaker {
|
||||||
if !p.has(rootPath, pathBackendCircuitBreakerExpression) {
|
if !p.has(rootPath, pathBackendCircuitBreakerExpression) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -162,7 +162,7 @@ func HasPrefix(labels map[string]string, prefix string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEnabled Check if a container is enabled in Træfik
|
// IsEnabled Check if a container is enabled in Traefik
|
||||||
func IsEnabled(labels map[string]string, exposedByDefault bool) bool {
|
func IsEnabled(labels map[string]string, exposedByDefault bool) bool {
|
||||||
return GetBoolValue(labels, TraefikEnable, exposedByDefault)
|
return GetBoolValue(labels, TraefikEnable, exposedByDefault)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ const (
|
||||||
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
|
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
|
||||||
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
|
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
|
||||||
SuffixBackendBuffering = "backend.buffering"
|
SuffixBackendBuffering = "backend.buffering"
|
||||||
|
SuffixBackendResponseForwardingFlushInterval = "backend.responseForwarding.flushInterval"
|
||||||
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
|
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
|
||||||
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
|
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
|
||||||
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
|
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
|
||||||
|
@ -133,6 +134,7 @@ const (
|
||||||
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
|
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
|
||||||
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
|
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
|
||||||
TraefikBackendBuffering = Prefix + SuffixBackendBuffering
|
TraefikBackendBuffering = Prefix + SuffixBackendBuffering
|
||||||
|
TraefikBackendResponseForwardingFlushInterval = Prefix + SuffixBackendResponseForwardingFlushInterval
|
||||||
TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes
|
TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes
|
||||||
TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes
|
TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes
|
||||||
TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes
|
TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes
|
||||||
|
|
|
@ -359,6 +359,19 @@ func GetHealthCheck(labels map[string]string) *types.HealthCheck {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResponseForwarding Create ResponseForwarding from labels
|
||||||
|
func GetResponseForwarding(labels map[string]string) *types.ResponseForwarding {
|
||||||
|
if !HasPrefix(labels, TraefikBackendResponseForwardingFlushInterval) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value := GetStringValue(labels, TraefikBackendResponseForwardingFlushInterval, "0")
|
||||||
|
|
||||||
|
return &types.ResponseForwarding{
|
||||||
|
FlushInterval: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetBuffering Create buffering from labels
|
// GetBuffering Create buffering from labels
|
||||||
func GetBuffering(labels map[string]string) *types.Buffering {
|
func GetBuffering(labels map[string]string) *types.Buffering {
|
||||||
if !HasPrefix(labels, TraefikBackendBuffering) {
|
if !HasPrefix(labels, TraefikBackendBuffering) {
|
||||||
|
|
|
@ -30,13 +30,14 @@ func (p *Provider) buildConfiguration(applications *marathon.Applications) *type
|
||||||
"getBackendName": p.getBackendName,
|
"getBackendName": p.getBackendName,
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getPort": getPort,
|
"getPort": getPort,
|
||||||
"getCircuitBreaker": label.GetCircuitBreaker,
|
"getCircuitBreaker": label.GetCircuitBreaker,
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
"getServers": p.getServers,
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
|
"getServers": p.getServers,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getSegmentNameSuffix": getSegmentNameSuffix,
|
"getSegmentNameSuffix": getSegmentNameSuffix,
|
||||||
|
@ -212,11 +213,14 @@ func (p *Provider) getFrontendRule(app appData) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := label.GetStringValue(app.SegmentLabels, label.TraefikDomain, p.Domain)
|
domain := label.GetStringValue(app.SegmentLabels, label.TraefikDomain, p.Domain)
|
||||||
|
if len(domain) > 0 {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
if len(app.SegmentName) > 0 {
|
if len(app.SegmentName) > 0 {
|
||||||
return "Host:" + strings.ToLower(provider.Normalize(app.SegmentName)) + "." + p.getSubDomain(app.ID) + "." + domain
|
return "Host:" + strings.ToLower(provider.Normalize(app.SegmentName)) + "." + p.getSubDomain(app.ID) + domain
|
||||||
}
|
}
|
||||||
return "Host:" + p.getSubDomain(app.ID) + "." + domain
|
return "Host:" + p.getSubDomain(app.ID) + domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPort(task marathon.Task, app appData) string {
|
func getPort(task marathon.Task, app appData) string {
|
||||||
|
|
|
@ -357,6 +357,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
withLabel(label.TraefikBackend, "foobar"),
|
withLabel(label.TraefikBackend, "foobar"),
|
||||||
|
|
||||||
withLabel(label.TraefikBackendCircuitBreakerExpression, "NetworkErrorRatio() > 0.5"),
|
withLabel(label.TraefikBackendCircuitBreakerExpression, "NetworkErrorRatio() > 0.5"),
|
||||||
|
withLabel(label.TraefikBackendResponseForwardingFlushInterval, "10ms"),
|
||||||
withLabel(label.TraefikBackendHealthCheckScheme, "http"),
|
withLabel(label.TraefikBackendHealthCheckScheme, "http"),
|
||||||
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
|
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
|
||||||
withLabel(label.TraefikBackendHealthCheckPort, "880"),
|
withLabel(label.TraefikBackendHealthCheckPort, "880"),
|
||||||
|
@ -591,6 +592,9 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -29,15 +29,16 @@ func (p *Provider) buildConfiguration(tasks []state.Task) *types.Configuration {
|
||||||
"getID": getID,
|
"getID": getID,
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getBackendName": getBackendName,
|
"getBackendName": getBackendName,
|
||||||
"getCircuitBreaker": label.GetCircuitBreaker,
|
"getCircuitBreaker": label.GetCircuitBreaker,
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
"getServers": p.getServers,
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
"getHost": p.getHost,
|
"getServers": p.getServers,
|
||||||
"getServerPort": p.getServerPort,
|
"getHost": p.getHost,
|
||||||
|
"getServerPort": p.getServerPort,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getSegmentNameSuffix": getSegmentNameSuffix,
|
"getSegmentNameSuffix": getSegmentNameSuffix,
|
||||||
|
@ -222,8 +223,11 @@ func (p *Provider) getFrontendRule(task taskData) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
domain := label.GetStringValue(task.TraefikLabels, label.TraefikDomain, p.Domain)
|
domain := label.GetStringValue(task.TraefikLabels, label.TraefikDomain, p.Domain)
|
||||||
|
if len(domain) > 0 {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
return "Host:" + p.getSegmentSubDomain(task) + "." + domain
|
return "Host:" + p.getSegmentSubDomain(task) + domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getServers(tasks []taskData) map[string]types.Server {
|
func (p *Provider) getServers(tasks []taskData) map[string]types.Server {
|
||||||
|
|
|
@ -314,6 +314,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
withLabel(label.TraefikBackend, "foobar"),
|
withLabel(label.TraefikBackend, "foobar"),
|
||||||
|
|
||||||
withLabel(label.TraefikBackendCircuitBreakerExpression, "NetworkErrorRatio() > 0.5"),
|
withLabel(label.TraefikBackendCircuitBreakerExpression, "NetworkErrorRatio() > 0.5"),
|
||||||
|
withLabel(label.TraefikBackendResponseForwardingFlushInterval, "10ms"),
|
||||||
withLabel(label.TraefikBackendHealthCheckScheme, "http"),
|
withLabel(label.TraefikBackendHealthCheckScheme, "http"),
|
||||||
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
|
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
|
||||||
withLabel(label.TraefikBackendHealthCheckPort, "880"),
|
withLabel(label.TraefikBackendHealthCheckPort, "880"),
|
||||||
|
@ -551,6 +552,9 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -20,12 +20,13 @@ func (p *Provider) buildConfiguration(services []rancherData) *types.Configurati
|
||||||
"getDomain": label.GetFuncString(label.TraefikDomain, p.Domain),
|
"getDomain": label.GetFuncString(label.TraefikDomain, p.Domain),
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getCircuitBreaker": label.GetCircuitBreaker,
|
"getCircuitBreaker": label.GetCircuitBreaker,
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
"getMaxConn": label.GetMaxConn,
|
"getMaxConn": label.GetMaxConn,
|
||||||
"getHealthCheck": label.GetHealthCheck,
|
"getHealthCheck": label.GetHealthCheck,
|
||||||
"getBuffering": label.GetBuffering,
|
"getBuffering": label.GetBuffering,
|
||||||
"getServers": getServers,
|
"getResponseForwarding": label.GetResponseForwarding,
|
||||||
|
"getServers": getServers,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getBackendName": getBackendName,
|
"getBackendName": getBackendName,
|
||||||
|
@ -128,7 +129,11 @@ func (p *Provider) serviceFilter(service rancherData) bool {
|
||||||
|
|
||||||
func (p *Provider) getFrontendRule(serviceName string, labels map[string]string) string {
|
func (p *Provider) getFrontendRule(serviceName string, labels map[string]string) string {
|
||||||
domain := label.GetStringValue(labels, label.TraefikDomain, p.Domain)
|
domain := label.GetStringValue(labels, label.TraefikDomain, p.Domain)
|
||||||
defaultRule := "Host:" + strings.ToLower(strings.Replace(serviceName, "/", ".", -1)) + "." + domain
|
if len(domain) > 0 {
|
||||||
|
domain = "." + domain
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRule := "Host:" + strings.ToLower(strings.Replace(serviceName, "/", ".", -1)) + domain
|
||||||
|
|
||||||
return label.GetStringValue(labels, label.TraefikFrontendRule, defaultRule)
|
return label.GetStringValue(labels, label.TraefikFrontendRule, defaultRule)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackend: "foobar",
|
label.TraefikBackend: "foobar",
|
||||||
|
|
||||||
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
label.TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
||||||
|
label.TraefikBackendResponseForwardingFlushInterval: "10ms",
|
||||||
label.TraefikBackendHealthCheckScheme: "http",
|
label.TraefikBackendHealthCheckScheme: "http",
|
||||||
label.TraefikBackendHealthCheckPath: "/health",
|
label.TraefikBackendHealthCheckPath: "/health",
|
||||||
label.TraefikBackendHealthCheckPort: "880",
|
label.TraefikBackendHealthCheckPort: "880",
|
||||||
|
@ -281,6 +282,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
CircuitBreaker: &types.CircuitBreaker{
|
CircuitBreaker: &types.CircuitBreaker{
|
||||||
Expression: "NetworkErrorRatio() > 0.5",
|
Expression: "NetworkErrorRatio() > 0.5",
|
||||||
},
|
},
|
||||||
|
ResponseForwarding: &types.ResponseForwarding{
|
||||||
|
FlushInterval: "10ms",
|
||||||
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
|
|
|
@ -53,10 +53,10 @@ func (r *Rules) host(hosts ...string) *mux.Route {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rules) hostRegexp(hosts ...string) *mux.Route {
|
func (r *Rules) hostRegexp(hostPatterns ...string) *mux.Route {
|
||||||
router := r.Route.Route.Subrouter()
|
router := r.Route.Route.Subrouter()
|
||||||
for _, host := range hosts {
|
for _, hostPattern := range hostPatterns {
|
||||||
router.Host(strings.ToLower(host))
|
router.Host(hostPattern)
|
||||||
}
|
}
|
||||||
return r.Route.Route
|
return r.Route.Route
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,6 +195,39 @@ func TestHostRegexp(t *testing.T) {
|
||||||
"http://barcom": false,
|
"http://barcom": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "regex insensitive",
|
||||||
|
hostExp: "{dummy:[A-Za-z-]+\\.bar\\.com}",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://FOO.bar.com": true,
|
||||||
|
"http://foo.bar.com": true,
|
||||||
|
"http://fooubar.com": false,
|
||||||
|
"http://barucom": false,
|
||||||
|
"http://barcom": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "insensitive host",
|
||||||
|
hostExp: "{dummy:[a-z-]+\\.bar\\.com}",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://FOO.bar.com": true,
|
||||||
|
"http://foo.bar.com": true,
|
||||||
|
"http://fooubar.com": false,
|
||||||
|
"http://barucom": false,
|
||||||
|
"http://barcom": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "insensitive host simple",
|
||||||
|
hostExp: "foo.bar.com",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://FOO.bar.com": true,
|
||||||
|
"http://foo.bar.com": true,
|
||||||
|
"http://fooubar.com": false,
|
||||||
|
"http://barucom": false,
|
||||||
|
"http://barcom": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
@ -212,7 +245,7 @@ func TestHostRegexp(t *testing.T) {
|
||||||
|
|
||||||
for testURL, match := range test.urls {
|
for testURL, match := range test.urls {
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, testURL, nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, testURL, nil)
|
||||||
assert.Equal(t, match, rt.Match(req, &mux.RouteMatch{}))
|
assert.Equal(t, match, rt.Match(req, &mux.RouteMatch{}), testURL)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -625,7 +625,7 @@ func buildProxyProtocolListener(entryPoint *configuration.EntryPoint, listener n
|
||||||
|
|
||||||
func (s *Server) buildInternalRouter(entryPointName string) *mux.Router {
|
func (s *Server) buildInternalRouter(entryPointName string) *mux.Router {
|
||||||
internalMuxRouter := mux.NewRouter()
|
internalMuxRouter := mux.NewRouter()
|
||||||
internalMuxRouter.StrictSlash(true)
|
internalMuxRouter.StrictSlash(!s.globalConfiguration.KeepTrailingSlash)
|
||||||
internalMuxRouter.SkipClean(true)
|
internalMuxRouter.SkipClean(true)
|
||||||
|
|
||||||
if entryPoint, ok := s.entryPoints[entryPointName]; ok && entryPoint.InternalRouter != nil {
|
if entryPoint, ok := s.entryPoints[entryPointName]; ok && entryPoint.InternalRouter != nil {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containous/flaeg/parse"
|
||||||
"github.com/containous/mux"
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/configuration"
|
"github.com/containous/traefik/configuration"
|
||||||
"github.com/containous/traefik/healthcheck"
|
"github.com/containous/traefik/healthcheck"
|
||||||
|
@ -42,13 +43,7 @@ func (s *Server) loadConfiguration(configMsg types.ConfigMessage) {
|
||||||
|
|
||||||
s.metricsRegistry.ConfigReloadsCounter().Add(1)
|
s.metricsRegistry.ConfigReloadsCounter().Add(1)
|
||||||
|
|
||||||
newServerEntryPoints, err := s.loadConfig(newConfigurations, s.globalConfiguration)
|
newServerEntryPoints := s.loadConfig(newConfigurations, s.globalConfiguration)
|
||||||
if err != nil {
|
|
||||||
s.metricsRegistry.ConfigReloadsFailureCounter().Add(1)
|
|
||||||
s.metricsRegistry.LastConfigReloadFailureGauge().Set(float64(time.Now().Unix()))
|
|
||||||
log.Error("Error loading new configuration, aborted ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.metricsRegistry.LastConfigReloadSuccessGauge().Set(float64(time.Now().Unix()))
|
s.metricsRegistry.LastConfigReloadSuccessGauge().Set(float64(time.Now().Unix()))
|
||||||
|
|
||||||
|
@ -77,11 +72,7 @@ func (s *Server) loadConfiguration(configMsg types.ConfigMessage) {
|
||||||
|
|
||||||
// loadConfig returns a new gorilla.mux Route from the specified global configuration and the dynamic
|
// loadConfig returns a new gorilla.mux Route from the specified global configuration and the dynamic
|
||||||
// provider configurations.
|
// provider configurations.
|
||||||
func (s *Server) loadConfig(configurations types.Configurations, globalConfiguration configuration.GlobalConfiguration) (map[string]*serverEntryPoint, error) {
|
func (s *Server) loadConfig(configurations types.Configurations, globalConfiguration configuration.GlobalConfiguration) map[string]*serverEntryPoint {
|
||||||
redirectHandlers, err := s.buildEntryPointRedirect()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
serverEntryPoints := s.buildServerEntryPoints()
|
serverEntryPoints := s.buildServerEntryPoints()
|
||||||
|
|
||||||
|
@ -95,7 +86,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
||||||
|
|
||||||
for _, frontendName := range frontendNames {
|
for _, frontendName := range frontendNames {
|
||||||
frontendPostConfigs, err := s.loadFrontendConfig(providerName, frontendName, config,
|
frontendPostConfigs, err := s.loadFrontendConfig(providerName, frontendName, config,
|
||||||
redirectHandlers, serverEntryPoints,
|
serverEntryPoints,
|
||||||
backendsHandlers, backendsHealthCheck)
|
backendsHandlers, backendsHealthCheck)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("%v. Skipping frontend %s...", err, frontendName)
|
log.Errorf("%v. Skipping frontend %s...", err, frontendName)
|
||||||
|
@ -118,8 +109,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
||||||
|
|
||||||
// Get new certificates list sorted per entrypoints
|
// Get new certificates list sorted per entrypoints
|
||||||
// Update certificates
|
// Update certificates
|
||||||
entryPointsCertificates, err := s.loadHTTPSConfiguration(configurations, globalConfiguration.DefaultEntryPoints)
|
entryPointsCertificates := s.loadHTTPSConfiguration(configurations, globalConfiguration.DefaultEntryPoints)
|
||||||
// FIXME error management
|
|
||||||
|
|
||||||
// Sort routes and update certificates
|
// Sort routes and update certificates
|
||||||
for serverEntryPointName, serverEntryPoint := range serverEntryPoints {
|
for serverEntryPointName, serverEntryPoint := range serverEntryPoints {
|
||||||
|
@ -129,12 +119,12 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverEntryPoints, err
|
return serverEntryPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) loadFrontendConfig(
|
func (s *Server) loadFrontendConfig(
|
||||||
providerName string, frontendName string, config *types.Configuration,
|
providerName string, frontendName string, config *types.Configuration,
|
||||||
redirectHandlers map[string]negroni.Handler, serverEntryPoints map[string]*serverEntryPoint,
|
serverEntryPoints map[string]*serverEntryPoint,
|
||||||
backendsHandlers map[string]http.Handler, backendsHealthCheck map[string]*healthcheck.BackendConfig,
|
backendsHandlers map[string]http.Handler, backendsHealthCheck map[string]*healthcheck.BackendConfig,
|
||||||
) ([]handlerPostConfig, error) {
|
) ([]handlerPostConfig, error) {
|
||||||
|
|
||||||
|
@ -174,7 +164,7 @@ func (s *Server) loadFrontendConfig(
|
||||||
postConfigs = append(postConfigs, postConfig)
|
postConfigs = append(postConfigs, postConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
fwd, err := s.buildForwarder(entryPointName, entryPoint, frontendName, frontend, responseModifier)
|
fwd, err := s.buildForwarder(entryPointName, entryPoint, frontendName, frontend, responseModifier, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create the forwarder for frontend %s: %v", frontendName, err)
|
return nil, fmt.Errorf("failed to create the forwarder for frontend %s: %v", frontendName, err)
|
||||||
}
|
}
|
||||||
|
@ -195,10 +185,6 @@ func (s *Server) loadFrontendConfig(
|
||||||
|
|
||||||
n := negroni.New()
|
n := negroni.New()
|
||||||
|
|
||||||
if _, exist := redirectHandlers[entryPointName]; exist {
|
|
||||||
n.Use(redirectHandlers[entryPointName])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, handler := range handlers {
|
for _, handler := range handlers {
|
||||||
n.Use(handler)
|
n.Use(handler)
|
||||||
}
|
}
|
||||||
|
@ -231,13 +217,21 @@ func (s *Server) loadFrontendConfig(
|
||||||
|
|
||||||
func (s *Server) buildForwarder(entryPointName string, entryPoint *configuration.EntryPoint,
|
func (s *Server) buildForwarder(entryPointName string, entryPoint *configuration.EntryPoint,
|
||||||
frontendName string, frontend *types.Frontend,
|
frontendName string, frontend *types.Frontend,
|
||||||
responseModifier modifyResponse) (http.Handler, error) {
|
responseModifier modifyResponse, backend *types.Backend) (http.Handler, error) {
|
||||||
|
|
||||||
roundTripper, err := s.getRoundTripper(entryPointName, frontend.PassTLSCert, entryPoint.TLS)
|
roundTripper, err := s.getRoundTripper(entryPointName, frontend.PassTLSCert, entryPoint.TLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create RoundTripper for frontend %s: %v", frontendName, err)
|
return nil, fmt.Errorf("failed to create RoundTripper for frontend %s: %v", frontendName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var flushInterval parse.Duration
|
||||||
|
if backend.ResponseForwarding != nil {
|
||||||
|
err := flushInterval.Set(backend.ResponseForwarding.FlushInterval)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error creating flush interval for frontend %s: %v", frontendName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var fwd http.Handler
|
var fwd http.Handler
|
||||||
fwd, err = forward.New(
|
fwd, err = forward.New(
|
||||||
forward.Stream(true),
|
forward.Stream(true),
|
||||||
|
@ -245,6 +239,7 @@ func (s *Server) buildForwarder(entryPointName string, entryPoint *configuration
|
||||||
forward.RoundTripper(roundTripper),
|
forward.RoundTripper(roundTripper),
|
||||||
forward.ResponseModifier(responseModifier),
|
forward.ResponseModifier(responseModifier),
|
||||||
forward.BufferPool(s.bufferPool),
|
forward.BufferPool(s.bufferPool),
|
||||||
|
forward.StreamingFlushInterval(time.Duration(flushInterval)),
|
||||||
forward.WebsocketConnectionClosedHook(func(req *http.Request, conn net.Conn) {
|
forward.WebsocketConnectionClosedHook(func(req *http.Request, conn net.Conn) {
|
||||||
server := req.Context().Value(http.ServerContextKey).(*http.Server)
|
server := req.Context().Value(http.ServerContextKey).(*http.Server)
|
||||||
if server != nil {
|
if server != nil {
|
||||||
|
@ -535,17 +530,15 @@ func (s *Server) postLoadConfiguration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadHTTPSConfiguration add/delete HTTPS certificate managed dynamically
|
// loadHTTPSConfiguration add/delete HTTPS certificate managed dynamically
|
||||||
func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, defaultEntryPoints configuration.DefaultEntryPoints) (map[string]map[string]*tls.Certificate, error) {
|
func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, defaultEntryPoints configuration.DefaultEntryPoints) map[string]map[string]*tls.Certificate {
|
||||||
newEPCertificates := make(map[string]map[string]*tls.Certificate)
|
newEPCertificates := make(map[string]map[string]*tls.Certificate)
|
||||||
// Get all certificates
|
// Get all certificates
|
||||||
for _, config := range configurations {
|
for _, config := range configurations {
|
||||||
if config.TLS != nil && len(config.TLS) > 0 {
|
if config.TLS != nil && len(config.TLS) > 0 {
|
||||||
if err := traefiktls.SortTLSPerEntryPoints(config.TLS, newEPCertificates, defaultEntryPoints); err != nil {
|
traefiktls.SortTLSPerEntryPoints(config.TLS, newEPCertificates, defaultEntryPoints)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newEPCertificates, nil
|
return newEPCertificates
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) buildServerEntryPoints() map[string]*serverEntryPoint {
|
func (s *Server) buildServerEntryPoints() map[string]*serverEntryPoint {
|
||||||
|
@ -613,7 +606,7 @@ func buildDefaultCertificate(defaultCertificate *traefiktls.Certificate) (*tls.C
|
||||||
func (s *Server) buildDefaultHTTPRouter() *mux.Router {
|
func (s *Server) buildDefaultHTTPRouter() *mux.Router {
|
||||||
rt := mux.NewRouter()
|
rt := mux.NewRouter()
|
||||||
rt.NotFoundHandler = s.wrapHTTPHandlerWithAccessLog(http.HandlerFunc(http.NotFound), "backend not found")
|
rt.NotFoundHandler = s.wrapHTTPHandlerWithAccessLog(http.HandlerFunc(http.NotFound), "backend not found")
|
||||||
rt.StrictSlash(true)
|
rt.StrictSlash(!s.globalConfiguration.KeepTrailingSlash)
|
||||||
rt.SkipClean(true)
|
rt.SkipClean(true)
|
||||||
return rt
|
return rt
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,7 @@ func TestServerLoadConfigHealthCheckOptions(t *testing.T) {
|
||||||
|
|
||||||
srv := NewServer(globalConfig, nil, entryPoints)
|
srv := NewServer(globalConfig, nil, entryPoints)
|
||||||
|
|
||||||
_, err := srv.loadConfig(dynamicConfigs, globalConfig)
|
_ = srv.loadConfig(dynamicConfigs, globalConfig)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedNumHealthCheckBackends := 0
|
expectedNumHealthCheckBackends := 0
|
||||||
if healthCheck != nil {
|
if healthCheck != nil {
|
||||||
|
@ -189,8 +188,7 @@ func TestServerLoadConfigEmptyBasicAuth(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := NewServer(globalConfig, nil, entryPoints)
|
srv := NewServer(globalConfig, nil, entryPoints)
|
||||||
_, err := srv.loadConfig(dynamicConfigs, globalConfig)
|
_ = srv.loadConfig(dynamicConfigs, globalConfig)
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerLoadCertificateWithDefaultEntryPoint(t *testing.T) {
|
func TestServerLoadCertificateWithDefaultEntryPoint(t *testing.T) {
|
||||||
|
@ -216,9 +214,9 @@ func TestServerLoadCertificateWithDefaultEntryPoint(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := NewServer(globalConfig, nil, entryPoints)
|
srv := NewServer(globalConfig, nil, entryPoints)
|
||||||
if mapEntryPoints, err := srv.loadConfig(dynamicConfigs, globalConfig); err != nil {
|
|
||||||
t.Fatalf("got error: %s", err)
|
mapEntryPoints := srv.loadConfig(dynamicConfigs, globalConfig)
|
||||||
} else if !mapEntryPoints["https"].certs.ContainsCertificates() {
|
if !mapEntryPoints["https"].certs.ContainsCertificates() {
|
||||||
t.Fatal("got error: https entryPoint must have TLS certificates.")
|
t.Fatal("got error: https entryPoint must have TLS certificates.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,10 +263,7 @@ func TestReuseBackend(t *testing.T) {
|
||||||
|
|
||||||
srv := NewServer(globalConfig, nil, entryPoints)
|
srv := NewServer(globalConfig, nil, entryPoints)
|
||||||
|
|
||||||
serverEntryPoints, err := srv.loadConfig(dynamicConfigs, globalConfig)
|
serverEntryPoints := srv.loadConfig(dynamicConfigs, globalConfig)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error loading config: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that the /ok path returns a status 200.
|
// Test that the /ok path returns a status 200.
|
||||||
responseRecorderOk := &httptest.ResponseRecorder{}
|
responseRecorderOk := &httptest.ResponseRecorder{}
|
||||||
|
|
|
@ -115,7 +115,8 @@ func (s *Server) buildLoadBalancer(frontendName string, backendName string, back
|
||||||
var saveFrontend http.Handler
|
var saveFrontend http.Handler
|
||||||
|
|
||||||
if s.accessLoggerMiddleware != nil {
|
if s.accessLoggerMiddleware != nil {
|
||||||
saveBackend := accesslog.NewSaveBackend(fwd, backendName)
|
saveUsername := accesslog.NewSaveUsername(fwd)
|
||||||
|
saveBackend := accesslog.NewSaveBackend(saveUsername, backendName)
|
||||||
saveFrontend = accesslog.NewSaveFrontend(saveBackend, frontendName)
|
saveFrontend = accesslog.NewSaveFrontend(saveBackend, frontendName)
|
||||||
rr, _ = roundrobin.New(saveFrontend)
|
rr, _ = roundrobin.New(saveFrontend)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -144,6 +144,14 @@ func (s *Server) buildServerEntryPointMiddlewares(serverEntryPointName string) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.entryPoints[serverEntryPointName].Configuration.Redirect != nil {
|
||||||
|
redirectHandlers, err := s.buildEntryPointRedirect()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create redirect middleware: %v", err)
|
||||||
|
}
|
||||||
|
serverMiddlewares = append(serverMiddlewares, redirectHandlers[serverEntryPointName])
|
||||||
|
}
|
||||||
|
|
||||||
if s.entryPoints[serverEntryPointName].Configuration.Auth != nil {
|
if s.entryPoints[serverEntryPointName].Configuration.Auth != nil {
|
||||||
authMiddleware, err := mauth.NewAuthenticator(s.entryPoints[serverEntryPointName].Configuration.Auth, s.tracingMiddleware)
|
authMiddleware, err := mauth.NewAuthenticator(s.entryPoints[serverEntryPointName].Configuration.Auth, s.tracingMiddleware)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -306,7 +314,8 @@ func buildIPWhiteLister(whiteList *types.WhiteList, ipStrategy *types.IPStrategy
|
||||||
|
|
||||||
func (s *Server) wrapNegroniHandlerWithAccessLog(handler negroni.Handler, frontendName string) negroni.Handler {
|
func (s *Server) wrapNegroniHandlerWithAccessLog(handler negroni.Handler, frontendName string) negroni.Handler {
|
||||||
if s.accessLoggerMiddleware != nil {
|
if s.accessLoggerMiddleware != nil {
|
||||||
saveBackend := accesslog.NewSaveNegroniBackend(handler, "Træfik")
|
saveUsername := accesslog.NewSaveNegroniUsername(handler)
|
||||||
|
saveBackend := accesslog.NewSaveNegroniBackend(saveUsername, "Traefik")
|
||||||
saveFrontend := accesslog.NewSaveNegroniFrontend(saveBackend, frontendName)
|
saveFrontend := accesslog.NewSaveNegroniFrontend(saveBackend, frontendName)
|
||||||
return saveFrontend
|
return saveFrontend
|
||||||
}
|
}
|
||||||
|
@ -315,7 +324,8 @@ func (s *Server) wrapNegroniHandlerWithAccessLog(handler negroni.Handler, fronte
|
||||||
|
|
||||||
func (s *Server) wrapHTTPHandlerWithAccessLog(handler http.Handler, frontendName string) http.Handler {
|
func (s *Server) wrapHTTPHandlerWithAccessLog(handler http.Handler, frontendName string) http.Handler {
|
||||||
if s.accessLoggerMiddleware != nil {
|
if s.accessLoggerMiddleware != nil {
|
||||||
saveBackend := accesslog.NewSaveBackend(handler, "Træfik")
|
saveUsername := accesslog.NewSaveUsername(handler)
|
||||||
|
saveBackend := accesslog.NewSaveBackend(saveUsername, "Traefik")
|
||||||
saveFrontend := accesslog.NewSaveFrontend(saveBackend, frontendName)
|
saveFrontend := accesslog.NewSaveFrontend(saveBackend, frontendName)
|
||||||
return saveFrontend
|
return saveFrontend
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,5 @@ func TestServerGenericFrontendAuthFail(t *testing.T) {
|
||||||
|
|
||||||
srv := NewServer(globalConfig, nil, entryPoints)
|
srv := NewServer(globalConfig, nil, entryPoints)
|
||||||
|
|
||||||
_, err := srv.loadConfig(dynamicConfigs, globalConfig)
|
_ = srv.loadConfig(dynamicConfigs, globalConfig)
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue