Compare commits

...

74 Commits

Author SHA1 Message Date
Fernandez Ludovic
8b8b1427f6 Prepare release v2.0.4 2019-10-28 21:10:50 +01:00
Ludovic Fernandez
e2d971f20e fix: release timeout. 2019-10-28 20:58:05 +01:00
Ludovic Fernandez
9d17e8826b Prepare release v2.0.3 2019-10-28 17:50:05 +01:00
Damien Duportal
531c581cd5 Fix a typo in routing documentation for Docker 2019-10-28 17:42:05 +01:00
Robert Baker
f790b9aa54 Add example for changing the port used by traefik to connect to a service 2019-10-28 15:50:06 +01:00
Ludovic Fernandez
8f000423ed fix: default tracing backend. 2019-10-28 12:26:05 +01:00
Daniel Tomcej
4990f6c22d Allow Default Certificate to work on macOS 10.15 2019-10-28 11:52:04 +01:00
mpl
d447a50b73 Prepare release v1.7.18 2019-10-28 11:52:04 +01:00
Ludovic Fernandez
cbecfad4df Prepare release v1.7.17 2019-10-28 11:52:04 +01:00
Nicholas Wiersma
770a7f11a7 Avoid closing stdout when the accesslog handler is closed
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
Co-authored-by: jlevesy <julien.levesy@containo.us>
2019-10-28 11:52:04 +01:00
Brad Jones
27a65f8745 Add note clarifying client certificate header 2019-10-28 11:52:04 +01:00
Ludovic Fernandez
5cd06c03f0 Prepare release v1.7.16 2019-10-28 11:52:04 +01:00
Ludovic Fernandez
43e5092c46 Prepare release v1.7.15 2019-10-28 11:52:04 +01:00
mpl
a239e3fba6 error pages: do not buffer response when it's not an error 2019-10-28 11:52:04 +01:00
Ludovic Fernandez
743d772a80 doc: @ is not authorized in names definition. 2019-10-28 11:04:05 +01:00
Damien Duportal
1f734630b9 Improve documentation of the router rules for API and dashboard 2019-10-25 17:32:04 +02:00
Ludovic Fernandez
355fe6195e Add documentation about backtick for rule definition. 2019-10-25 17:16:05 +02:00
Sylvain Rabot
d22bd5b42d Fix ldflags using incorrect pkg url 2019-10-25 16:48:06 +02:00
Ludovic Fernandez
5327ce543b Remove unnecessary reload of the configuration. 2019-10-25 15:46:05 +02:00
Ludovic Fernandez
3747eb59ea fix: deep copy of passHostHeader on ServersLoadBalancer. 2019-10-25 14:40:05 +02:00
Ludovic Fernandez
2b00ab3432 fix: skip akamai url verify. 2019-10-25 14:02:09 +02:00
Michael
a6cdd701e2 Set proxy protocol logger to DEBUG level 2019-10-24 10:02:06 +02:00
Sylvain Rabot
c8984e6a6a Use debug for log about skipping addition of cert 2019-10-24 01:10:04 +02:00
Florian Perrot
9179aa52cf Fix Security Headers Doc 2019-10-23 11:48:05 +02:00
sumarsono
2042fdf3bd fix typo for stripPrefix in tab File (YAML) 2019-10-20 23:40:03 +02:00
remche
d1c3372dc4 fix ForwardAuth tls.skipverify examples 2019-10-18 11:50:05 +02:00
Ludovic Fernandez
3884a68889 fix: add stacktrace when recover. 2019-10-18 11:30:05 +02:00
Kenneth Peiruza
0ec84ec597 Adding support for HTTPs backends with Kubernetes ExternalName services 2019-10-18 11:12:05 +02:00
Oisin Canty
6a9d21e9aa Fix spelling mistake: "founded" -> "found" 2019-10-18 10:54:05 +02:00
Sylvain Rabot
a829d44b51 Let instana/go-sensor handle default agent host 2019-10-16 22:30:05 +02:00
Adrian Goins
554e3e9e6e fix incorrect DNS reference 2019-10-16 16:40:04 +02:00
Michael G
904b3b5b0b Remove obsolete v2 remark from README 2019-10-16 16:26:05 +02:00
Peter Stalman
02bdc1dcb9 Clarify unit of duration field in access log 2019-10-16 10:34:04 +02:00
Ludovic Fernandez
b586ae2f25 Remove deadcode. 2019-10-15 16:36:05 +02:00
Damien Duportal
8492a702b2 Migration guide: pathprefixstrip migration 2019-10-14 17:26:05 +02:00
Antoine Caron
0048156379 chore(node/webui): update node to 12.11 version 2019-10-14 17:18:04 +02:00
Ludovic Fernandez
cb3328dca3 Normalize service and router names for ingress. 2019-10-14 11:18:04 +02:00
Ludovic Fernandez
e7b7ae94b0 fix: add filename in the file provider logs. 2019-10-11 17:20:05 +02:00
Jan Sauer
17ce295c30 Fix acme storage file docker mounting example 2019-10-11 14:34:06 +02:00
Ludovic Fernandez
d5e3bb1b6d Prepare release v2.0.2 2019-10-09 19:12:05 +02:00
Jean-Baptiste Doumenjou
7e4e5ec6e4 Add a service sticky details vue component 2019-10-09 17:34:05 +02:00
Ludovic Fernandez
f2656e62dc fix: default router name for k8s ingress. 2019-10-09 17:16:07 +02:00
cthompson527
83de97e547 fix misspelling on documentation landing page 2019-10-09 16:56:05 +02:00
Pierre-Yves Aillet
b552efe770 Update apiVersion in documentation descriptor 2019-10-09 14:56:04 +02:00
Ludovic Fernandez
1663c7c8e7 fix: ovh client int overflow. 2019-10-09 14:48:04 +02:00
Ludovic Fernandez
1a6bef1a7e doc: update issues and PRs templates. 2019-10-09 14:28:04 +02:00
Ludovic Fernandez
ff31e75ccc ci: reduce memory consumption of the linter 2019-10-09 11:48:04 +02:00
Constantin Stan
c87a37f804 Improve ciphersuite examples 2019-10-08 14:38:04 +02:00
Sebastiaan
76ead096aa Update 04-ingressroutes.yml 2019-10-07 15:20:06 +02:00
Jan Sauer
668ff71470 Replace ambiguous cli help message wording 2019-10-07 15:12:05 +02:00
Constantin Stan
538d5e8be4 TLS_RSA_WITH_AES_256_GCM_SHA384 is considered weak 2019-10-07 15:02:06 +02:00
Andreas Steinel
b2b142a037 State clearly, that they are mutual exclusive 2019-10-07 14:48:05 +02:00
Damien Duportal
3ebed4ff40 Clarifies how to configure and access the dashboard in the api & dashboard documentations 2019-10-07 14:38:06 +02:00
XciD
a2cd69b654 Fix typo in log 2019-10-07 13:12:05 +02:00
Emile Vauge
cfc14671ed Remove deprecated videos 2019-10-07 12:52:22 +02:00
Olivier Beaudoin
ed4b2f74ff Update scope of services and middlewares 2019-10-07 12:50:04 +02:00
Sebastiaan
dd53be7a1b typo in cli command 2019-10-07 12:32:07 +02:00
Julian Maestri
c83d7916c9 fix: typo in healthCheck examples 2019-10-07 10:14:04 +02:00
Julian Maestri
0865962f8d fix: remove extra backtick from routers docs 2019-10-07 09:58:03 +02:00
Sandro
9691085bc2 Fix yaml domains example 2019-10-07 09:48:04 +02:00
Andreas Steinel
b243d1c599 Add overview to API documentation 2019-10-07 09:38:04 +02:00
Constantin Stan
db6e404bda Typo in documentation 2019-10-02 16:32:05 +02:00
Jean-Baptiste Doumenjou
6f63e24dbb Add a response forwarding section to the service documentation 2019-10-01 13:26:04 +02:00
Andreas Steinel
0082fe8173 $ needs escaping in docker-compose.yml 2019-09-30 18:32:04 +02:00
mpl
06d37b2a94 document providersThrottleDuration 2019-09-30 18:24:04 +02:00
Ludovic Fernandez
48f11900d3 fix: default passHostHeader for file provider. 2019-09-30 18:12:04 +02:00
Ludovic Fernandez
230cd28ac9 fix: return an error instead of panic. 2019-09-30 17:52:04 +02:00
mpl
86261f2b0a document serversTransport 2019-09-30 17:16:05 +02:00
Ludovic Fernandez
30ad00fa65 doc: fix influxDB and statsD case in configuration page. 2019-09-30 14:56:05 +02:00
Ludovic Fernandez
33a1499bdd fix: panic with metrics recorder. 2019-09-30 14:42:04 +02:00
Jean-Baptiste Doumenjou
211fa18ac2 Add the pass host header section to the services documentation 2019-09-30 11:26:06 +02:00
Joas Souza
4c5250e850 Fix misleading text 2019-09-30 09:12:04 +02:00
Grégoire Pineau
788024685f Fixed typo in routing/providers/docker documentation 2019-09-27 13:08:03 +02:00
dat-gitto-kid
b5f07d2995 Change instances of "dymanic" to "dynamic" 2019-09-26 18:20:04 +02:00
99 changed files with 1820 additions and 901 deletions

View File

@@ -1,3 +1,7 @@
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
### Do you want to request a *feature* or report a *bug*?
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
@@ -8,21 +12,12 @@ For end-user related support questions, please refer to one of the following:
-->
### Do you want to request a *feature* or report a *bug*?
<!--
If you intend to ask a support question: DO NOT FILE AN ISSUE.
-->
### Did you try using a 1.7.x configuration for the version 2.0?
- [ ] Yes
- [ ] No
Bug
<!--
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
The configurations between 1.X and 2.X are NOT compatible.
Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
-->
@@ -30,7 +25,7 @@ If you just checked the "Yes" box, be aware that this is probably not a bug. The
<!--
HOW TO WRITE A GOOD ISSUE?
HOW TO WRITE A GOOD BUG REPORT?
- Respect the issue template as much as possible.
- The title should be short and descriptive.
@@ -52,13 +47,12 @@ HOW TO WRITE A GOOD ISSUE?
### Output of `traefik version`: (_What version of Traefik are you using?_)
<!--
`latest` is not considered as a valid version.
For the Traefik Docker image:
docker run [IMAGE] version
ex: docker run traefik version
For the alpine Traefik Docker image:
docker run [IMAGE] traefik version
ex: docker run traefik traefik version
-->
```
@@ -70,12 +64,13 @@ For the alpine Traefik Docker image:
```toml
# (paste your configuration here)
```
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output at DEBUG level (`--log.level=DEBUG` switch)
### If applicable, please paste the log output in DEBUG level (`--log.level=DEBUG` switch)
```
(paste your output here)

View File

@@ -3,6 +3,9 @@ name: Bug report
about: Create a report to help us improve
---
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
### Do you want to request a *feature* or report a *bug*?
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
@@ -14,19 +17,12 @@ For end-user related support questions, please refer to one of the following:
-->
### Do you want to request a *feature* or report a *bug*?
Bug
### Did you try using a 1.7.x configuration for the version 2.0?
- [ ] Yes
- [ ] No
<!--
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
The configurations between 1.X and 2.X are NOT compatible.
Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
-->
@@ -56,13 +52,12 @@ HOW TO WRITE A GOOD BUG REPORT?
### Output of `traefik version`: (_What version of Traefik are you using?_)
<!--
`latest` is not considered as a valid version.
For the Traefik Docker image:
docker run [IMAGE] version
ex: docker run traefik version
For the alpine Traefik Docker image:
docker run [IMAGE] traefik version
ex: docker run traefik traefik version
-->
```

View File

@@ -3,6 +3,9 @@ name: Feature request
about: Suggest an idea for this project
---
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->
### Do you want to request a *feature* or report a *bug*?
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
@@ -14,9 +17,6 @@ For end-user related support questions, please refer to one of the following:
-->
### Do you want to request a *feature* or report a *bug*?
Feature
### What did you expect to see?

View File

@@ -1,18 +1,19 @@
<!--
PLEASE READ THIS MESSAGE.
HOW TO WRITE A GOOD PULL REQUEST?
Documentation fixes or enhancements:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.0
- Make it small.
- Do only one thing.
- Avoid re-formatting.
- Make sure the code builds.
- Make sure all tests pass.
- Add tests.
- Write useful descriptions and titles.
- Address review comments in terms of additional commits.
- Do not amend/squash existing ones unless the PR is trivial.
- Read the contributing guide: https://github.com/containous/traefik/blob/master/CONTRIBUTING.md.
Bug fixes:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.0
Enhancements:
- for Traefik v1: we only accept bug fixes
- for Traefik v2: use branch master
HOW TO WRITE A GOOD PULL REQUEST? https://docs.traefik.io/contributing/submitting-pull-requests/
-->

View File

@@ -1,6 +1,9 @@
[run]
deadline = "10m"
timeout = "10m"
skip-files = []
skip-dirs = [
"pkg/provider/kubernetes/crd/generated/",
]
[linters-settings]
@@ -40,9 +43,11 @@
"scopelint",
"gochecknoinits",
"gochecknoglobals",
# "godox", # manage TODO FIXME ## wait for https://github.com/golangci/golangci-lint/issues/337
"godox",
"gocognit",
"bodyclose", # Too many false-positive and panics.
# "stylecheck", # skip because report issues related to some generated files. ## wait for https://github.com/golangci/golangci-lint/issues/337
"wsl", # Too strict
"stylecheck", # skip because report issues related to some generated files.
]
[issues]

View File

@@ -1,3 +1,81 @@
## [v2.0.4](https://github.com/containous/traefik/tree/v2.0.4) (2019-10-28)
[All Commits](https://github.com/containous/traefik/compare/v2.0.3...v2.0.4)
Fixes releases system.
Same changelog as v2.0.3.
## [v2.0.3](https://github.com/containous/traefik/tree/v2.0.3) (2019-10-28)
[All Commits](https://github.com/containous/traefik/compare/v2.0.2...v2.0.3)
**Bug fixes:**
- **[acme,logs]** Use debug for log about skipping addition of cert ([#5641](https://github.com/containous/traefik/pull/5641) by [sylr](https://github.com/sylr))
- **[file]** fix: add filename in the file provider logs. ([#5636](https://github.com/containous/traefik/pull/5636) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd,k8s/ingress]** Remove unnecessary reload of the configuration. ([#5707](https://github.com/containous/traefik/pull/5707) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd,k8s/ingress]** Fixing support for HTTPs backends with Kubernetes ExternalName services ([#5660](https://github.com/containous/traefik/pull/5660) by [kpeiruza](https://github.com/kpeiruza))
- **[k8s,k8s/ingress]** Normalize service and router names for ingress. ([#5623](https://github.com/containous/traefik/pull/5623) by [ldez](https://github.com/ldez))
- **[logs]** Set proxy protocol logger to DEBUG level ([#5712](https://github.com/containous/traefik/pull/5712) by [mmatur](https://github.com/mmatur))
- **[middleware]** fix: add stacktrace when recover. ([#5654](https://github.com/containous/traefik/pull/5654) by [ldez](https://github.com/ldez))
- **[tracing]** Let instana/go-sensor handle default agent host ([#5658](https://github.com/containous/traefik/pull/5658) by [sylr](https://github.com/sylr))
- **[tracing]** fix: default tracing backend. ([#5717](https://github.com/containous/traefik/pull/5717) by [ldez](https://github.com/ldez))
- fix: deep copy of passHostHeader on ServersLoadBalancer. ([#5720](https://github.com/containous/traefik/pull/5720) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme]** Fix acme storage file docker mounting example ([#5633](https://github.com/containous/traefik/pull/5633) by [jansauer](https://github.com/jansauer))
- **[acme]** fix incorrect DNS reference ([#5666](https://github.com/containous/traefik/pull/5666) by [oskapt](https://github.com/oskapt))
- **[logs]** Clarify unit of duration field in access log ([#5664](https://github.com/containous/traefik/pull/5664) by [Sarke](https://github.com/Sarke))
- **[middleware]** Fix Security Headers Doc ([#5706](https://github.com/containous/traefik/pull/5706) by [FlorianPerrot](https://github.com/FlorianPerrot))
- **[middleware]** Migration guide: pathprefixstrip migration ([#5600](https://github.com/containous/traefik/pull/5600) by [dduportal](https://github.com/dduportal))
- **[middleware]** fix ForwardAuth tls.skipverify examples ([#5683](https://github.com/containous/traefik/pull/5683) by [remche](https://github.com/remche))
- **[rules]** Add documentation about backtick for rule definition. ([#5714](https://github.com/containous/traefik/pull/5714) by [ldez](https://github.com/ldez))
- **[webui]** Improve documentation of the router rules for API and dashboard ([#5625](https://github.com/containous/traefik/pull/5625) by [dduportal](https://github.com/dduportal))
- doc: @ is not authorized in names definition. ([#5734](https://github.com/containous/traefik/pull/5734) by [ldez](https://github.com/ldez))
- Remove obsolete v2 remark from README ([#5669](https://github.com/containous/traefik/pull/5669) by [dragetd](https://github.com/dragetd))
- Fix spelling mistake: &#34;founded&#34; -&gt; &#34;found&#34; ([#5674](https://github.com/containous/traefik/pull/5674) by [ocanty](https://github.com/ocanty))
- fix typo for stripPrefix in tab File (YAML) ([#5694](https://github.com/containous/traefik/pull/5694) by [nalakawula](https://github.com/nalakawula))
- Add example for changing the port used by traefik to connect to a service ([#5224](https://github.com/containous/traefik/pull/5224) by [robertbaker](https://github.com/robertbaker))
**Misc:**
- **[logs,middleware]** Cherry pick v1.7 into v2.0 ([#5735](https://github.com/containous/traefik/pull/5735) by [jbdoumenjou](https://github.com/jbdoumenjou))
## [v2.0.2](https://github.com/containous/traefik/tree/v2.0.2) (2019-10-09)
[All Commits](https://github.com/containous/traefik/compare/v2.0.1...v2.0.2)
**Bug fixes:**
- **[acme]** fix: ovh client int overflow. ([#5607](https://github.com/containous/traefik/pull/5607) by [ldez](https://github.com/ldez))
- **[api,k8s,k8s/ingress]** fix: default router name for k8s ingress. ([#5612](https://github.com/containous/traefik/pull/5612) by [ldez](https://github.com/ldez))
- **[file]** fix: default passHostHeader for file provider. ([#5516](https://github.com/containous/traefik/pull/5516) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd]** Fix typo in log ([#5590](https://github.com/containous/traefik/pull/5590) by [XciD](https://github.com/XciD))
- **[middleware,metrics]** fix: panic with metrics recorder. ([#5536](https://github.com/containous/traefik/pull/5536) by [ldez](https://github.com/ldez))
- **[webui]** Add a service sticky details vue component ([#5579](https://github.com/containous/traefik/pull/5579) by [jbdoumenjou](https://github.com/jbdoumenjou))
- fix: return an error instead of panic. ([#5549](https://github.com/containous/traefik/pull/5549) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme,file]** Fix yaml domains example ([#5569](https://github.com/containous/traefik/pull/5569) by [SuperSandro2000](https://github.com/SuperSandro2000))
- **[api,webui]** Clarifies how to configure and access the dashboard in the api &amp; dashboard documentations ([#5523](https://github.com/containous/traefik/pull/5523) by [dduportal](https://github.com/dduportal))
- **[api]** Add overview to API documentation ([#5539](https://github.com/containous/traefik/pull/5539) by [lnxbil](https://github.com/lnxbil))
- **[cli]** typo in cli command ([#5586](https://github.com/containous/traefik/pull/5586) by [basraven](https://github.com/basraven))
- **[cli]** Replace ambiguous cli help message wording ([#5233](https://github.com/containous/traefik/pull/5233) by [jansauer](https://github.com/jansauer))
- **[docker]** Fixed typo in routing/providers/docker documentation ([#5520](https://github.com/containous/traefik/pull/5520) by [lyrixx](https://github.com/lyrixx))
- **[docker]** $ needs escaping in docker-compose.yml ([#5528](https://github.com/containous/traefik/pull/5528) by [lnxbil](https://github.com/lnxbil))
- **[file]** State clearly, that they are mutual exclusive ([#5527](https://github.com/containous/traefik/pull/5527) by [lnxbil](https://github.com/lnxbil))
- **[healthcheck]** fix: typo in healthCheck examples ([#5575](https://github.com/containous/traefik/pull/5575) by [serpi90](https://github.com/serpi90))
- **[k8s/crd]** Update 04-ingressroutes.yml ([#5585](https://github.com/containous/traefik/pull/5585) by [basraven](https://github.com/basraven))
- **[k8s/crd]** Update apiVersion in documentation descriptor ([#5605](https://github.com/containous/traefik/pull/5605) by [pyaillet](https://github.com/pyaillet))
- **[metrics]** doc: fix influxDB and statsD case in configuration page. ([#5531](https://github.com/containous/traefik/pull/5531) by [ldez](https://github.com/ldez))
- **[middleware]** Update scope of services and middlewares ([#5584](https://github.com/containous/traefik/pull/5584) by [Thoorium](https://github.com/Thoorium))
- **[middleware]** Typo in documentation ([#5558](https://github.com/containous/traefik/pull/5558) by [Constans](https://github.com/Constans))
- **[middleware]** Fix misleading text ([#5540](https://github.com/containous/traefik/pull/5540) by [joassouza](https://github.com/joassouza))
- **[tls]** document serversTransport ([#5529](https://github.com/containous/traefik/pull/5529) by [mpl](https://github.com/mpl))
- **[tls]** TLS_RSA_WITH_AES_256_GCM_SHA384 is considered weak ([#5578](https://github.com/containous/traefik/pull/5578) by [Constans](https://github.com/Constans))
- **[tls]** Improve ciphersuite examples ([#5594](https://github.com/containous/traefik/pull/5594) by [Constans](https://github.com/Constans))
- Remove deprecated videos ([#5570](https://github.com/containous/traefik/pull/5570) by [emilevauge](https://github.com/emilevauge))
- fix: remove extra backtick from routers docs ([#5572](https://github.com/containous/traefik/pull/5572) by [serpi90](https://github.com/serpi90))
- document providersThrottleDuration ([#5519](https://github.com/containous/traefik/pull/5519) by [mpl](https://github.com/mpl))
- Add a response forwarding section to the service documentation ([#5517](https://github.com/containous/traefik/pull/5517) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Change instances of &#34;dymanic&#34; to &#34;dynamic&#34; ([#5504](https://github.com/containous/traefik/pull/5504) by [dat-gitto-kid](https://github.com/dat-gitto-kid))
- Add the pass host header section to the services documentation ([#5500](https://github.com/containous/traefik/pull/5500) by [jbdoumenjou](https://github.com/jbdoumenjou))
- fix misspelling on documentation landing page ([#5613](https://github.com/containous/traefik/pull/5613) by [cthompson527](https://github.com/cthompson527))
## [v2.0.1](https://github.com/containous/traefik/tree/v2.0.1) (2019-09-26)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0...v2.0.1)
@@ -31,6 +109,24 @@
- Add the router priority documentation ([#5481](https://github.com/containous/traefik/pull/5481) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Improve the Migration Guide ([#5391](https://github.com/containous/traefik/pull/5391) by [jbdoumenjou](https://github.com/jbdoumenjou))
## [v1.7.18](https://github.com/containous/traefik/tree/v1.7.18) (2019-09-23)
[All Commits](https://github.com/containous/traefik/compare/v1.7.17...v1.7.18)
**Bug fixes:**
- **[go,security]** This version is compiled with [Go 1.12.10](https://groups.google.com/d/msg/golang-announce/cszieYyuL9Q/g4Z7pKaqAgAJ), which fixes a vulnerability in previous versions. See the [CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16276) about it for more details.
## [v1.7.17](https://github.com/containous/traefik/tree/v1.7.17) (2019-09-23)
[All Commits](https://github.com/containous/traefik/compare/v1.7.16...v1.7.17)
**Bug fixes:**
- **[logs,middleware]** Avoid closing stdout when the accesslog handler is closed ([#5459](https://github.com/containous/traefik/pull/5459) by [nrwiersma](https://github.com/nrwiersma))
- **[middleware]** Actually send header and code during WriteHeader, if needed ([#5404](https://github.com/containous/traefik/pull/5404) by [mpl](https://github.com/mpl))
**Documentation:**
- **[k8s]** Add note clarifying client certificate header ([#5362](https://github.com/containous/traefik/pull/5362) by [bradjones1](https://github.com/bradjones1))
- **[webui]** Update docs links. ([#5412](https://github.com/containous/traefik/pull/5412) by [ldez](https://github.com/ldez))
- Update Traefik image version. ([#5399](https://github.com/containous/traefik/pull/5399) by [ldez](https://github.com/ldez))
## [v2.0.0](https://github.com/containous/traefik/tree/v2.0.0) (2019-09-16)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-alpha1...v2.0.0)
@@ -375,6 +471,29 @@
- fix a service with one server .yaml example ([#5373](https://github.com/containous/traefik/pull/5373) by [zaverden](https://github.com/zaverden))
- fix: services configuration documentation. ([#5359](https://github.com/containous/traefik/pull/5359) by [ldez](https://github.com/ldez))
## [v1.7.16](https://github.com/containous/traefik/tree/v1.7.16) (2019-09-13)
[All Commits](https://github.com/containous/traefik/compare/v1.7.15...v1.7.16)
**Bug fixes:**
- **[middleware,websocket]** implement Flusher and Hijacker for codeCatcher ([#5376](https://github.com/containous/traefik/pull/5376) by [mpl](https://github.com/mpl))
## [v1.7.15](https://github.com/containous/traefik/tree/v1.7.15) (2019-09-12)
[All Commits](https://github.com/containous/traefik/compare/v1.7.14...v1.7.15)
**Bug fixes:**
- **[authentication,k8s/ingress]** Kubernetes support for Auth.HeaderField ([#5235](https://github.com/containous/traefik/pull/5235) by [ErikWegner](https://github.com/ErikWegner))
- **[k8s,k8s/ingress]** Finish kubernetes throttling refactoring ([#5269](https://github.com/containous/traefik/pull/5269) by [mpl](https://github.com/mpl))
- **[k8s]** Throttle Kubernetes config refresh ([#4716](https://github.com/containous/traefik/pull/4716) by [benweissmann](https://github.com/benweissmann))
- **[k8s]** Fix wrong handling of insecure tls auth forward ingress annotation ([#5319](https://github.com/containous/traefik/pull/5319) by [majkrzak](https://github.com/majkrzak))
- **[middleware]** error pages: do not buffer response when it&#39;s not an error ([#5285](https://github.com/containous/traefik/pull/5285) by [mpl](https://github.com/mpl))
- **[tls]** Consider default cert domain in certificate store ([#5353](https://github.com/containous/traefik/pull/5353) by [nrwiersma](https://github.com/nrwiersma))
- **[tls]** Add TLS minversion constraint ([#5356](https://github.com/containous/traefik/pull/5356) by [dtomcej](https://github.com/dtomcej))
**Documentation:**
- **[acme]** Update Acme doc - Vultr Wildcard &amp; Root ([#5320](https://github.com/containous/traefik/pull/5320) by [ddymko](https://github.com/ddymko))
- **[consulcatalog]** Typo in basic auth usersFile label consul-catalog ([#5230](https://github.com/containous/traefik/pull/5230) by [pitan](https://github.com/pitan))
- **[logs]** Improve Access Logs Documentation page ([#5238](https://github.com/containous/traefik/pull/5238) by [dduportal](https://github.com/dduportal))
## [v2.0.0-rc3](https://github.com/containous/traefik/tree/v2.0.0-rc3) (2019-09-10)
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-rc2...v2.0.0-rc3)

View File

@@ -1,3 +1,4 @@
# Contributing
See <https://docs.traefik.io/v2.0/contributing/thank-you/>.
- https://docs.traefik.io/contributing/submitting-pull-requests/
- https://docs.traefik.io/contributing/submitting-issues/

View File

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

View File

@@ -33,7 +33,7 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
---
:warning: Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
:warning: Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
## Overview
@@ -87,10 +87,11 @@ You can access the simple HTML frontend of Traefik.
## Documentation
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
You can find the complete documentation of Traefik v2 at [https://docs.traefik.io](https://docs.traefik.io).
:warning: If you're testing out v2, please ensure you are using the [v2 documentation](https://docs.traefik.io/).
If you are using Traefik v1, you can find the complete documentation at [https://docs.traefik.io/v1.7/](https://docs.traefik.io/v1.7/)
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
## Support
@@ -121,17 +122,7 @@ git clone https://github.com/containous/traefik
## Introductory Videos
:warning: Please be aware that these videos are for v1.X. The old configurations for Traefik v1.X are NOT compatible with Traefik v2. If you're running v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/).
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at GopherCon 2017.
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)
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
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)
You can find high level and deep dive videos on [videos.containo.us](https://videos.containo.us)
## Maintainers

View File

@@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
&& chmod +x /usr/local/bin/go-bindata
# Download golangci-lint binary to bin folder in $GOPATH
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.18.0
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.20.0
# Download golangci-lint and misspell binary to bin folder in $GOPATH
RUN GO111MODULE=off go get github.com/client9/misspell/cmd/misspell

View File

@@ -15,7 +15,7 @@ import (
func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLoader) *cli.Command {
return &cli.Command{
Name: "healthcheck",
Description: `Calls Traefik /ping to check the health of Traefik (the API must be enabled).`,
Description: `Calls Traefik /ping endpoint (disabled by default) to check the health of Traefik.`,
Configuration: traefikConfiguration,
Run: runCmd(traefikConfiguration),
Resources: loaders,

View File

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

View File

@@ -219,7 +219,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) |
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) |
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
| [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` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` [^5] | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
@@ -247,6 +247,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) |
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
| manual | - | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
@@ -277,6 +278,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
[^4]: `docker stack` remark: there is no way to support terminal attached to container when deploying with `docker stack`, so you might need to run container with `docker run -it` to generate certificates using `manual` provider.
[^5]: The `Global API Key` needs to be used, not the `Origin CA Key`.
!!! info "`delayBeforeCheck`"
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
@@ -380,7 +382,7 @@ ACME certificates can be stored in a JSON file that needs to have a `600` file m
In Docker you can mount either the JSON file, or the folder containing it:
```bash
docker run -v "/my/host/acme.json:acme.json" traefik
docker run -v "/my/host/acme.json:/acme.json" traefik
```
```bash

View File

@@ -191,8 +191,7 @@ See [cipherSuites](https://godoc.org/crypto/tls#pkg-constants) for more informat
[tls.options]
[tls.options.default]
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384"
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
```
@@ -204,7 +203,6 @@ tls:
default:
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_GCM_SHA384
```
```yaml tab="Kubernetes"
@@ -217,7 +215,6 @@ metadata:
spec:
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_GCM_SHA384
```
!!! important "TLS 1.3"

View File

@@ -20,4 +20,4 @@ Developing Traefik, our main goal is to make it simple to use, and we're sure yo
!!! info
If you're a businness running critical services behind Traefik, know that [Containous](https://containo.us), the company that sponsors Traefik's development, can provide [commercial support](https://containo.us/services/#commercial-support) and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.
If you're a business running critical services behind Traefik, know that [Containous](https://containo.us), the company that sponsors Traefik's development, can provide [commercial support](https://containo.us/services/#commercial-support) and develops an [Enterprise Edition](https://containo.us/traefikee/) of Traefik.

View File

@@ -474,7 +474,8 @@ metadata:
spec:
forwardAuth:
address: https://authserver.com/auth
insecureSkipVerify: true
tls:
insecureSkipVerify: true
```
```json tab="Marathon"
@@ -492,7 +493,8 @@ labels:
[http.middlewares]
[http.middlewares.test-auth.forwardAuth]
address = "https://authserver.com/auth"
insecureSkipVerify: true
[http.middlewares.test-auth.forwardAuth.tls]
insecureSkipVerify: true
```
```yaml tab="File (YAML)"
@@ -501,5 +503,6 @@ http:
test-auth:
forwardAuth:
address: "https://authserver.com/auth"
insecureSkipVerify: true
tls:
insecureSkipVerify: true
```

View File

@@ -162,8 +162,8 @@ labels:
```toml tab="File (TOML)"
[http.middlewares]
[http.middlewares.testHeader.headers]
FrameDeny = true
SSLRedirect = true
frameDeny = true
sslRedirect = true
```
```yaml tab="File (YAML)"
@@ -171,8 +171,8 @@ http:
middlewares:
testHeader:
headers:
FrameDeny: true
SSLRedirect: true
frameDeny: true
sslRedirect: true
```
### CORS Headers
@@ -235,7 +235,7 @@ http:
middlewares:
testHeader:
headers:
accessControlAllowMethod:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT

View File

@@ -183,14 +183,14 @@ and therefore this specification would be ignored even if present.
routes:
- match: Host(`bar.com`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: add-foo-prefix@file
# namespace: bar
# A namespace specification such as above is ignored
# when the cross-provider syntax is used.
services:
- name: whoami
port: 80
middlewares:
- name: add-foo-prefix@file
# namespace: bar
# A namespace specification such as above is ignored
# when the cross-provider syntax is used.
```
## Available Middlewares

View File

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

View File

@@ -7,7 +7,7 @@ Redirecting the Client to a Different Scheme/Port
TODO: add schema
-->
RegexRedirect redirect request from a scheme to another.
RedirectScheme redirect request from a scheme to another.
## Configuration Examples

View File

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

View File

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

View File

@@ -4,12 +4,12 @@ To enable the InfluxDB:
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
```
```yaml tab="File (YAML)"
metrics:
influxdb: {}
influxDB: {}
```
```bash tab="CLI"
@@ -24,13 +24,13 @@ Address instructs exporter to send metrics to influxdb at this address.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
address = "localhost:8089"
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
address: localhost:8089
```
@@ -46,13 +46,13 @@ InfluxDB's address protocol (udp or http).
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
protocol = "udp"
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
protocol: udp
```
@@ -68,13 +68,13 @@ InfluxDB database used when protocol is http.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
database = ""
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
database: ""
```
@@ -90,13 +90,13 @@ InfluxDB retention policy used when protocol is http.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
retentionPolicy = ""
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
retentionPolicy: ""
```
@@ -112,13 +112,13 @@ InfluxDB username (only with http).
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
username = ""
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
username: ""
```
@@ -134,13 +134,13 @@ InfluxDB password (only with http).
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
password = ""
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
password: ""
```
@@ -156,13 +156,13 @@ Enable metrics on entry points.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
addEntryPointsLabels = true
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
addEntryPointsLabels: true
```
@@ -178,13 +178,13 @@ Enable metrics on services.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
addServicesLabels = true
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
addServicesLabels: true
```
@@ -200,13 +200,13 @@ The interval used by the exporter to push metrics to influxdb.
```toml tab="File (TOML)"
[metrics]
[metrics.influxdb]
[metrics.influxDB]
pushInterval = 10s
```
```yaml tab="File (YAML)"
metrics:
influxdb:
influxDB:
pushInterval: 10s
```

View File

@@ -114,5 +114,5 @@ metrics:
```bash tab="CLI"
--entryPoints.metrics.address=":8082"
--metrics.prometheus..entryPoint="metrics"
--metrics.prometheus.entryPoint="metrics"
```

View File

@@ -4,12 +4,12 @@ To enable the Statsd:
```toml tab="File (TOML)"
[metrics]
[metrics.statsd]
[metrics.statsD]
```
```yaml tab="File (YAML)"
metrics:
statsd: {}
statsD: {}
```
```bash tab="CLI"
@@ -24,13 +24,13 @@ Address instructs exporter to send metrics to statsd at this address.
```toml tab="File (TOML)"
[metrics]
[metrics.statsd]
[metrics.statsD]
address = "localhost:8125"
```
```yaml tab="File (YAML)"
metrics:
statsd:
statsD:
address: localhost:8125
```
@@ -46,13 +46,13 @@ Enable metrics on entry points.
```toml tab="File (TOML)"
[metrics]
[metrics.statsd]
[metrics.statsD]
addEntryPointsLabels = true
```
```yaml tab="File (YAML)"
metrics:
statsd:
statsD:
addEntryPointsLabels: true
```
@@ -68,13 +68,13 @@ Enable metrics on services.
```toml tab="File (TOML)"
[metrics]
[metrics.statsd]
[metrics.statsD]
addServicesLabels = true
```
```yaml tab="File (YAML)"
metrics:
statsd:
statsD:
addServicesLabels: true
```
@@ -90,13 +90,13 @@ The interval used by the exporter to push metrics to statsD.
```toml tab="File (TOML)"
[metrics]
[metrics.statsd]
[metrics.statsD]
pushInterval = 10s
```
```yaml tab="File (YAML)"
metrics:
statsd:
statsD:
pushInterval: 10s
```

View File

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

View File

@@ -14,7 +14,7 @@ In production, it should be at least secured by authentication and authorization
A good sane default (non exhaustive) set of recommendations
would be to apply the following protection mechanisms:
* At the transport level:
* At the transport level:
NOT publicly exposing the API's port,
keeping it restricted to internal networks
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
@@ -23,13 +23,16 @@ would be to apply the following protection mechanisms:
If you enable the API, a new special `service` named `api@internal` is created and can then be referenced in a router.
To enable the API handler:
To enable the API handler, use the following option on the
[static configuration](../getting-started/configuration-overview.md#the-static-configuration):
```toml tab="File (TOML)"
# Static Configuration
[api]
```
```yaml tab="File (YAML)"
# Static Configuration
api: {}
```
@@ -37,11 +40,13 @@ api: {}
--api=true
```
And then you will be able to reference it like this:
And then define a routing configuration on Traefik itself with the
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration):
```yaml tab="Docker"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
@@ -49,40 +54,42 @@ labels:
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
"traefik.http.routers.api.service": "api@internal"
"traefik.http.routers.api.middlewares": "auth"
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
"traefik.http.routers.api.service": "api@internal",
"traefik.http.routers.api.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="Rancher"
# Declaring the user list
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```toml tab="File (TOML)"
# Dynamic Configuration
[http.routers.my-api]
rule="PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
rule="Host(`traefik.domain.com`)
service="api@internal"
middlewares=["auth"]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:
routers:
api:
rule: PathPrefix(`/api`) || PathPrefix(`/dashboard`)
rule: Host(`traefik.domain.com`)
service: api@internal
middlewares:
- auth
@@ -90,10 +97,32 @@ http:
auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
??? warning "The router's [rule](../../routing/routers#rule) must catch requests for the URI path `/api`"
Using an "Host" rule is recommended, by catching all the incoming traffic on this host domain to the API.
However, you can also use "path prefix" rule or any combination or rules.
```bash tab="Host Rule"
# Matches http://traefik.domain.com, http://traefik.domain.com/api
# or http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`)"
```
```bash tab="Path Prefix Rule"
# Matches http://api.traefik.domain.com/api or http://domain.com/api
# but does not match http://api.traefik.domain.com/hello
rule = "PathPrefix(`/api`)"
```
```bash tab="Combination of Rules"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
```
### `insecure`
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`.
@@ -135,6 +164,9 @@ api:
--api.dashboard=true
```
!!! warning "With Dashboard enabled, the router [rule](../../routing/routers#rule) must catch requests for both `/api` and `/dashboard`"
Please check the [Dashboard documentation](./dashboard.md#dashboard-router-rule) to learn more about this and to get examples.
### `debug`
_Optional, Default=false_
@@ -159,24 +191,25 @@ api:
All the following endpoints must be accessed with a `GET` HTTP request.
| Path | Description |
|--------------------------------|-------------------------------------------------------------------------------------------|
| `/api/http/routers` | Lists all the HTTP routers information. |
| `/api/http/routers/{name}` | Returns the information of the HTTP router specified by `name`. |
| `/api/http/services` | Lists all the HTTP services information. |
| `/api/http/services/{name}` | Returns the information of the HTTP service specified by `name`. |
| `/api/http/middlewares` | Lists all the HTTP middlewares information. |
| `/api/http/middlewares/{name}` | Returns the information of the HTTP middleware specified by `name`. |
| `/api/tcp/routers` | Lists all the TCP routers information. |
| `/api/tcp/routers/{name}` | Returns the information of the TCP router specified by `name`. |
| `/api/tcp/services` | Lists all the TCP services information. |
| `/api/tcp/services/{name}` | Returns the information of the TCP service specified by `name`. |
| `/api/entrypoints` | Lists all the entry points information. |
| `/api/entrypoints/{name}` | Returns the information of the entry point specified by `name`. |
| `/api/version` | Returns information about Traefik version. |
| `/debug/vars` | See the [expvar](https://golang.org/pkg/expvar/) Go documentation. |
| `/debug/pprof/` | See the [pprof Index](https://golang.org/pkg/net/http/pprof/#Index) Go documentation. |
| `/debug/pprof/cmdline` | See the [pprof Cmdline](https://golang.org/pkg/net/http/pprof/#Cmdline) Go documentation. |
| `/debug/pprof/profile` | See the [pprof Profile](https://golang.org/pkg/net/http/pprof/#Profile) Go documentation. |
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |
| Path | Description |
|--------------------------------|---------------------------------------------------------------------------------------------|
| `/api/http/routers` | Lists all the HTTP routers information. |
| `/api/http/routers/{name}` | Returns the information of the HTTP router specified by `name`. |
| `/api/http/services` | Lists all the HTTP services information. |
| `/api/http/services/{name}` | Returns the information of the HTTP service specified by `name`. |
| `/api/http/middlewares` | Lists all the HTTP middlewares information. |
| `/api/http/middlewares/{name}` | Returns the information of the HTTP middleware specified by `name`. |
| `/api/tcp/routers` | Lists all the TCP routers information. |
| `/api/tcp/routers/{name}` | Returns the information of the TCP router specified by `name`. |
| `/api/tcp/services` | Lists all the TCP services information. |
| `/api/tcp/services/{name}` | Returns the information of the TCP service specified by `name`. |
| `/api/entrypoints` | Lists all the entry points information. |
| `/api/entrypoints/{name}` | Returns the information of the entry point specified by `name`. |
| `/api/overview` | Returns statistic information about http and tcp as well as enabled features and providers. |
| `/api/version` | Returns information about Traefik version. |
| `/debug/vars` | See the [expvar](https://golang.org/pkg/expvar/) Go documentation. |
| `/debug/pprof/` | See the [pprof Index](https://golang.org/pkg/net/http/pprof/#Index) Go documentation. |
| `/debug/pprof/cmdline` | See the [pprof Cmdline](https://golang.org/pkg/net/http/pprof/#Cmdline) Go documentation. |
| `/debug/pprof/profile` | See the [pprof Profile](https://golang.org/pkg/net/http/pprof/#Profile) Go documentation. |
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |

View File

@@ -3,24 +3,33 @@
See What's Going On
{: .subtitle }
The dashboard is the central place that shows you the current active routes handled by Traefik.
The dashboard is the central place that shows you the current active routes handled by Traefik.
<figure>
<img src="../../assets/img/webui-dashboard.png" alt="Dashboard - Providers" />
<figcaption>The dashboard in action</figcaption>
</figure>
By default, the dashboard is available on `/dashboard` on port `:8080`.
There is also a redirect of `/` to `/dashboard`, but one should not rely on that property as it is bound to change,
and it might make for confusing routing rules anyway.
The dashboard is available at the same location as the [API](./api.md) but on the path `/dashboard/` by default.
!!! info "Did You Know?"
It is possible to customize the dashboard endpoint.
To learn how, refer to the [API documentation](./api.md)
## Enabling the Dashboard
!!! warning "The trailing slash `/` in `/dashboard/` is mandatory"
To enable the dashboard, you need to enable [Traefik's API](./api.md).
There are 2 ways to configure and access the dashboard:
- [Secure mode (Recommended)](#secure-mode)
- [Insecure mode](#insecure-mode)
!!! note ""
There is also a redirect of the path `/` to the path `/dashboard/`,
but one should not rely on that property as it is bound to change,
and it might make for confusing routing rules anyway.
## Secure Mode
This is the **recommended** method.
Start by enabling the dashboard by using the following option from [Traefik's API](./api.md)
on the [static configuration](../getting-started/configuration-overview.md#the-static-configuration):
```toml tab="File (TOML)"
[api]
@@ -51,12 +60,125 @@ api:
--api.dashboard=true
```
!!! important "API/Dashboard Security"
To secure your dashboard, the use of a `service` named `api@internal` is mandatory and requires the definition of a router using one or more security [middlewares](../middlewares/overview.md)
like authentication ([basicAuth](../middlewares/basicauth.md) , [digestAuth](../middlewares/digestauth.md), [forwardAuth](../middlewares/forwardauth.md)) or [whitelisting](../middlewares/ipwhitelist.md).
More information about `api@internal` can be found in the [API documentation](./api.md#configuration)
Then define a routing configuration on Traefik itself,
with a router attached to the service `api@internal` in the
[dynamic configuration](../getting-started/configuration-overview.md#the-dynamic-configuration),
to allow defining:
!!! info "Did You Know?"
The API provides more features than the Dashboard.
To learn more about it, refer to the [API documentation](./api.md)
- One or more security features through [middlewares](../middlewares/overview.md)
like authentication ([basicAuth](../middlewares/basicauth.md) , [digestAuth](../middlewares/digestauth.md),
[forwardAuth](../middlewares/forwardauth.md)) or [whitelisting](../middlewares/ipwhitelist.md).
- A [router rule](#dashboard-router-rule) for accessing the dashboard,
through Traefik itself (sometimes referred as "Traefik-ception").
??? example "Dashboard Dynamic Configuration Examples"
```yaml tab="Docker"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "Host(`traefik.domain.com`)",
"traefik.http.routers.api.service": "api@internal",
"traefik.http.routers.api.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="Rancher"
# Dynamic Configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.domain.com`)
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```toml tab="File (TOML)"
# Dynamic Configuration
[http.routers.my-api]
rule="Host(`traefik.domain.com`)
service="api@internal"
middlewares=["auth"]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:
routers:
api:
rule: Host(`traefik.domain.com`)
service: api@internal
middlewares:
- auth
middlewares:
auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
### Dashboard Router Rule
As underlined in the [documentation for the `api.dashboard` option](./api.md#dashboard),
the [router rule](../routing/routers/index.md#rule) defined for Traefik must match
the path prefixes `/api` and `/dashboard`.
We recommend to use a "Host Based rule" as ```Host(`traefik.domain.com`)``` to match everything on the host domain,
or to make sure that the defined rule captures both prefixes:
```bash tab="Host Rule"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
rule = "Host(`traefik.domain.com`)"
```
```bash tab="Path Prefix Rule"
# Matches http://traefik.domain.com/api , http://domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
```
```bash tab="Combination of Rules"
# Matches http://traefik.domain.com/api or http://traefik.domain.com/dashboard
# but does not match http://traefik.domain.com/hello
rule = "Host(`traefik.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
```
## Insecure Mode
This mode is not recommended because it does not allow the use of security features.
To enable the "insecure mode", use the following options from [Traefik's API](./api.md#insecure):
```toml tab="File (TOML)"
[api]
dashboard = true
insecure = true
```
```yaml tab="File (YAML)"
api:
dashboard: true
insecure: true
```
```bash tab="CLI"
--api.dashboard=true --api.insecure=true
```
You can now access the dashboard on the port `8080` of the Traefik instance,
at the following URL: `http://<Traefik IP>:8080/dashboard/` (trailing slash is mandatory).

View File

@@ -29,6 +29,9 @@ You can customize the `entryPoint` where the `/ping` is active with the `entryPo
|---------|---------------|-----------------------------------------------------------------------------------------------------|
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
!!! note
The `cli` comes with a [`healthcheck`](./cli.md#healthcheck) command which can be used for calling this endpoint.
### `entryPoint`
Enabling /ping on a dedicated EntryPoint.

View File

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

View File

@@ -4,7 +4,7 @@ Good Old Configuration File
{: .subtitle }
The file provider lets you define the [dynamic configuration](./overview.md) in a TOML or YAML file.
You can write these configuration elements:
You can write one of these mutually exclusive configuration elements:
* In [a dedicated file](#filename)
* In [several dedicated files](#directory)

View File

@@ -39,6 +39,38 @@ Below is the list of the currently supported providers in Traefik.
The current version of Traefik doesn't support (yet) every provider.
See the [previous version (v1.7)](https://docs.traefik.io/v1.7/) for more providers.
### Configuration reload frequency
In some cases, some providers might undergo a sudden burst of changes,
which would generate a lot of configuration change events.
If Traefik took them all into account,
that would trigger a lot more configuration reloads than what is necessary,
or even useful.
In order to mitigate that, the `providers.providersThrottleDuration` option can be set.
It is the duration that Traefik waits for, after a configuration reload,
before taking into account any new configuration refresh event.
If any event arrives during that duration, only the most recent one is taken into account,
and all the previous others are dropped.
This option cannot be set per provider,
but the throttling algorithm applies independently to each of them.
It defaults to 2 seconds.
```toml tab="File (TOML)"
[providers]
providers.providersThrottleDuration = 10s
```
```yaml tab="File (YAML)"
providers:
providersThrottleDuration: 10s
```
```bash tab="CLI"
--providers.providersThrottleDuration=10s
```
<!--
TODO (document TCP VS HTTP dynamic configuration)
-->

View File

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

View File

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

View File

@@ -235,3 +235,168 @@ http:
servers:
- address: xx.xx.xx.xx:xx
```
## Transport configuration
Most of what happens to the connection between the clients and Traefik,
and then between Traefik and the backend servers, is configured through the
[entrypoints](../entrypoints) and the [routers](../routers).
In addition, a few parameters are dedicated to configuring globally
what happens with the connections between Traefik and the backends.
This is done through the `serversTransport` section of the configuration,
which features these options:
### `insecureSkipVerify`
_Optional, Default=false_
`insecureSkipVerify` disables SSL certificate verification.
```toml tab="File (TOML)"
## Static configuration
[serversTransport]
insecureSkipVerify = true
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
insecureSkipVerify: true
```
```bash tab="CLI"
## Static configuration
--serversTransport.insecureSkipVerify=true
```
### `rootCAs`
_Optional_
`rootCAs` is the list of certificates (as file paths, or data bytes)
that will be set as Root Certificate Authorities when using a self-signed TLS certificate.
```toml tab="File (TOML)"
## Static configuration
[serversTransport]
rootCAs = ["foo.crt", "bar.crt"]
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
rootCAs:
- foo.crt
- bar.crt
```
```bash tab="CLI"
## Static configuration
--serversTransport.rootCAs=foo.crt,bar.crt
```
### `maxIdleConnsPerHost`
_Optional, Default=2_
If non-zero, `maxIdleConnsPerHost` controls the maximum idle (keep-alive) connections to keep per-host.
```toml tab="File (TOML)"
## Static configuration
[serversTransport]
maxIdleConnsPerHost = 7
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
maxIdleConnsPerHost: 7
```
```bash tab="CLI"
## Static configuration
--serversTransport.maxIdleConnsPerHost=7
```
### `forwardingTimeouts`
`forwardingTimeouts` is about a number of timeouts relevant to when forwarding requests to the backend servers.
#### forwardingTimeouts.dialTimeout`
_Optional, Default=30s_
`dialTimeout` is the maximum duration allowed for a connection to a backend server to be established.
Zero means no timeout.
```toml tab="File (TOML)"
## Static configuration
[serversTransport.forwardingTimeouts]
dialTimeout = "1s"
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
forwardingTimeouts:
dialTimeout: 1s
```
```bash tab="CLI"
## Static configuration
--serversTransport.forwardingTimeouts.dialTimeout=1s
```
#### forwardingTimeouts.responseHeaderTimeout`
_Optional, Default=0s_
`responseHeaderTimeout`, if non-zero, specifies the amount of time to wait for a server's response headers
after fully writing the request (including its body, if any).
This time does not include the time to read the response body.
Zero means no timeout.
```toml tab="File (TOML)"
## Static configuration
[serversTransport.forwardingTimeouts]
responseHeaderTimeout = "1s"
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
forwardingTimeouts:
responseHeaderTimeout: 1s
```
```bash tab="CLI"
## Static configuration
--serversTransport.forwardingTimeouts.responseHeaderTimeout=1s
```
#### forwardingTimeouts.idleConnTimeout`
_Optional, Default=90s_
`idleConnTimeout`, is the maximum amount of time an idle (keep-alive) connection
will remain idle before closing itself.
Zero means no limit.
```toml tab="File (TOML)"
## Static configuration
[serversTransport.forwardingTimeouts]
idleConnTimeout = "1s"
```
```yaml tab="File (YAML)"
## Static configuration
serversTransport:
forwardingTimeouts:
idleConnTimeout: 1s
```
```bash tab="CLI"
## Static configuration
--serversTransport.forwardingTimeouts.idleConnTimeout=1s
```

View File

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

View File

@@ -52,6 +52,8 @@ add labels starting with `traefik.http.routers.{router-name-of-your-choice}.` an
For example, to change the routing rule, you could add the label ```"traefik.http.routers.routername.rule": "Host(`mydomain.com`)"```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
@@ -139,6 +141,8 @@ add labels starting with `traefik.http.services.{service-name-of-your-choice}.`,
For example, to change the passHostHeader behavior, you'd add the label `"traefik.http.services.servicename.loadbalancer.passhostheader": "false"`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
Registers a port.
@@ -157,7 +161,8 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
<!-- TODO doc passHostHeader in services page -->
See [pass Host header](../services/index.md#pass-host-header) for more information.
```json
"traefik.http.services.myservice.loadbalancer.passhostheader": "true"
@@ -252,10 +257,9 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
<!-- TODO doc responseforwarding in services page -->
FlushInterval specifies the flush interval to flush to the client while copying the response body.
See [response forwarding](../services/index.md#response-forwarding) for more information.
```json
"traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval": "10"
```
@@ -268,6 +272,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```json

View File

@@ -57,6 +57,8 @@ To update the configuration of the Router automatically attached to the containe
For example, to change the rule, you could add the label ```traefik.http.routers.my-container.rule=Host(`mydomain.com`)```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
@@ -145,6 +147,8 @@ add labels starting with `traefik.http.services.{name-of-your-choice}.`, followe
For example, to change the `passHostHeader` behavior,
you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
Registers a port.
@@ -163,7 +167,8 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
<!-- TODO doc passHostHeader in services page -->
See [pass Host header](../services/index.md#pass-host-header) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.passhostheader=true"
@@ -258,10 +263,9 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
<!-- TODO doc responseforwarding in services page -->
FlushInterval specifies the flush interval to flush to the client while copying the response body.
See [response forwarding](../services/index.md#response-forwarding) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval=10"
```
@@ -274,6 +278,8 @@ For example, to declare a middleware [`redirectscheme`](../../middlewares/redire
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```yaml

View File

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

View File

@@ -84,6 +84,8 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie
## Configuring HTTP Routers
!!! warning "The character `@` is not authorized in the router name"
### EntryPoints
If not specified, HTTP routers will accept requests from all defined entry points.
@@ -203,9 +205,14 @@ If you want to limit the router scope to a set of entry points, set the `entryPo
### Rule
Rules are a set of matchers that determine if a particular request matches specific criteria.
Rules are a set of matchers configured with values, that determine if a particular request matches specific criteria.
If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.
??? tip "Backticks or Quotes?"
To set the value of a rule, use [backticks](https://en.wiktionary.org/wiki/backtick) ``` ` ``` or escaped double-quotes `\"`.
Single quotes `'` are not accepted as values are [Golang's String Literals](https://golang.org/ref/spec#String_literals).
!!! example "Host is traefik.io"
```toml
@@ -229,7 +236,7 @@ The table below lists all the available matchers:
| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
| ```Path(`/path`, `/articles/{category}/{id:[0-9]+}`, ...)``` | Match exact request path. It accepts a sequence of literal and regular expression paths. |
| ```PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`)``` | Match request prefix path. It accepts a sequence of literal and regular expression prefix paths. |
| ```Query(`foo=bar`, `bar=baz`)``` | Match` Query String parameters. It accepts a sequence of key=value pairs. |
| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. |
!!! important "Regexp Syntax"
@@ -337,6 +344,8 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
You can attach a list of [middlewares](../../middlewares/overview.md) to each HTTP router.
The middlewares will take effect only if the rule matches, and before forwarding the request to the service.
!!! warning "The character `@` is not authorized in the middleware name."
!!! tip "Middlewares order"
Middlewares are applied in the same order as their declaration in **router**.
@@ -376,6 +385,8 @@ but there are exceptions for label-based providers.
See the specific [docker](../providers/docker.md#service-definition), [rancher](../providers/rancher.md#service-definition),
or [marathon](../providers/marathon.md#service-definition) documentation.
!!! warning "The character `@` is not authorized in the middleware name."
!!! important "HTTP routers can only target HTTP services (not TCP services)."
### TLS
@@ -479,8 +490,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
[tls.options.foo]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384"
]
```
@@ -500,8 +514,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
foo:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_GCM_SHA384
```
!!! important "Conflicting TLS Options"
@@ -596,7 +613,8 @@ http:
certResolver: "bar"
domains:
- main: "snitest.com"
sans: "*.snitest.com"
sans:
- "*.snitest.com"
```
[ACME v2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) supports wildcard certificates.
@@ -617,6 +635,8 @@ The [supported `provider` table](../../https/acme.md#providers) indicates if the
## Configuring TCP Routers
!!! warning "The character `@` is not authorized in the router name"
### General
If both HTTP routers and TCP routers listen to the same entry points, the TCP routers will apply *before* the HTTP routers.
@@ -851,8 +871,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
[tls.options.foo]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384"
]
```
@@ -872,8 +895,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
foo:
minVersion: VersionTLS12
cipherSuites:
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
- "TLS_RSA_WITH_AES_256_GCM_SHA384"
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
```
#### `certResolver`
@@ -925,5 +951,6 @@ tcp:
certResolver: "bar"
domains:
- main: "snitest.com"
sans: "*.snitest.com"
sans:
- "*.snitest.com"
```

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ metadata:
---
kind: Deployment
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
namespace: default
name: traefik
@@ -49,7 +49,7 @@ spec:
---
kind: Deployment
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
namespace: default
name: whoami

View File

@@ -2,6 +2,7 @@ apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: simpleingressroute
namespace: default
spec:
entryPoints:
- web
@@ -17,6 +18,7 @@ apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls
namespace: default
spec:
entryPoints:
- websecure

View File

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

View File

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

View File

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

13
go.mod
View File

@@ -39,7 +39,7 @@ require (
github.com/felixge/httpsnoop v1.0.0 // indirect
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
github.com/go-acme/lego/v3 v3.0.2
github.com/go-acme/lego/v3 v3.1.0
github.com/go-check/check v0.0.0-00010101000000-000000000000
github.com/go-kit/kit v0.9.0
github.com/golang/protobuf v1.3.2
@@ -51,7 +51,6 @@ require (
github.com/huandu/xstrings v1.2.0 // indirect
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
github.com/instana/go-sensor v1.4.17-0.20190515112224-78c14625025a
github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10 // indirect
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591
@@ -72,13 +71,11 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/philhofer/fwd v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang v1.0.0
github.com/prometheus/client_golang v1.1.0
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
github.com/prometheus/common v0.6.0 // indirect
github.com/prometheus/procfs v0.0.3 // indirect
github.com/rancher/go-rancher-metadata v0.0.0-00010101000000-000000000000
github.com/sirupsen/logrus v1.4.2
github.com/stretchr/testify v1.3.0
github.com/stretchr/testify v1.4.0
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13
github.com/tinylib/msgp v1.0.2 // indirect
github.com/transip/gotransip v5.8.2+incompatible // indirect
@@ -89,9 +86,9 @@ require (
github.com/vdemeester/shakers v0.1.0
github.com/vulcand/oxy v1.0.0
github.com/vulcand/predicate v1.1.0
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect
google.golang.org/grpc v1.22.1
gopkg.in/DataDog/dd-trace-go.v1 v1.16.1

41
go.sum
View File

@@ -78,6 +78,8 @@ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/c0va23/go-proxyprotocol v0.9.1 h1:5BCkp0fDJOhzzH1lhjUgHhmZz9VvRMMif1U2D31hb34=
github.com/c0va23/go-proxyprotocol v0.9.1/go.mod h1:TNjUV+llvk8TvWJxlPYAeAYZgSzT/iicNr3nWBWX320=
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
@@ -85,8 +87,8 @@ github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.10.0 h1:wJPNqfrQO0w3fCiQcf/2T4lR2y6Q2fAwRszllljgb8I=
github.com/cloudflare/cloudflare-go v0.10.0/go.mod h1:fOESqHl/jzAmCtEyjceLkw3v0rVjzl8V9iehxZPynXY=
github.com/cloudflare/cloudflare-go v0.10.2 h1:VBodKICVPnwmDxstcW3biKcDSpFIfS/RELUXsZSBYK4=
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
@@ -113,6 +115,7 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpu/goacmedns v0.0.1 h1:GeIU5chKys9zmHgOAgP+bstRaLqcGQ6HJh/hLw9hrus=
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -178,8 +181,9 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 h1:df6OFl8WNXk82xxP3R9ZPZ5seOA8XZkwLdbEzZF1/xI=
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2/go.mod h1:GLyXJD41gBO/NPKVPGQbhyyC06eugGy15QEZyUkE2/s=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-acme/lego/v3 v3.0.2 h1:cnS+URiPzkt2pd7I2WlZtFyt2ihQ762nouBybY4djjw=
github.com/go-acme/lego/v3 v3.0.2/go.mod h1:sMoLjf8BUo4Jexg+6Xw5KeFx98KVZ7Nfczh9tzLyhJU=
github.com/go-acme/lego/v3 v3.1.0 h1:yanYFoYW8azFkCvJfIk7edWWfjkYkhDxe45ZsxoW4Xk=
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-ini/ini v1.44.0 h1:8+SRbfpRFlIunpSum4BEf1ClTtVjOgKzgBv9pHFkI6w=
@@ -226,6 +230,8 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -287,6 +293,8 @@ github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBv
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
@@ -304,11 +312,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labbsr0x/bindman-dns-webhook v1.0.0 h1:gooRvyQtVOCtV/l9ZCI4CManZeVN/kUWG/vugRqHqv4=
github.com/labbsr0x/bindman-dns-webhook v1.0.0/go.mod h1:pn4jcNjxSywRWDPDyGkFzgSnwty18OFdiUFc6S6fpgc=
github.com/labbsr0x/goh v0.0.0-20190417202808-8b16b4848295/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I=
github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10 h1:mrPTy7qNJPGHaUkkN301r8Y+13l2/vsiC8Lvi09e6sI=
github.com/labbsr0x/goh v0.0.0-20190830205702-3d6988c73e10/go.mod h1:RBxeaayaaMmp7GxwHiKANjkg9e+rxjOm4mB5vD5rt/I=
github.com/labbsr0x/bindman-dns-webhook v1.0.2 h1:I7ITbmQPAVwrDdhd6dHKi+MYJTJqPCK0jE6YNBAevnk=
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad h1:nTyRWZ864mnHUnusBCVA628AZFgfGHwRUpbHqGhRQr8=
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad/go.mod h1:GyCk/ifDcqsU1tsRMMWqXANnTtxzcwEWscb7j5qmblM=
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807 h1:/7J1WDQd6Xn1Pr8KtE2I/7/cKw66AV3hBUOyxqyXo84=
@@ -317,6 +324,8 @@ github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591 h1:+zkZyvOy
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591/go.mod h1:EBQ0jeOrBpOTkquwjmJl4W6z5xqlf5oA2LZfTqRNcO0=
github.com/linode/linodego v0.10.0 h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jvM=
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
github.com/liquidweb/liquidweb-go v1.6.0 h1:vIj1I/Wf97fUnyirD+bi6Y63c0GiXk9nKI1+sFFl3G0=
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
github.com/looplab/fsm v0.1.0 h1:Qte7Zdn/5hBNbXzP7yxVU4OIFHWXBovyTT2LaBTyC20=
github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
@@ -346,6 +355,7 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@@ -414,6 +424,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
@@ -432,10 +444,12 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhD
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sacloud/libsacloud v1.26.1 h1:td3Kd7lvpSAxxHEVpnaZ9goHmmhi0D/RfP0Rqqf/kek=
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@@ -454,6 +468,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13 h1:WYRIgR83bWdH2zjqXalfLuQYtgBG1KKxDRxinx2ygMI=
github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8=
@@ -474,7 +490,7 @@ github.com/unrolled/render v1.0.1 h1:VDDnQQVfBMsOsp3VaCJszSO0nkBIVEYoPWeRThk9spY
github.com/unrolled/render v1.0.1/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM=
github.com/unrolled/secure v1.0.4 h1:DksfKsRTyXP2R8quDdOOuRpRO45VprFL0X9t9+JX1PU=
github.com/unrolled/secure v1.0.4/go.mod h1:R6rugAuzh4TQpbFAq69oqZggyBQxFRFQIewtz5z7Jsc=
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vdemeester/shakers v0.1.0 h1:K+n9sSyUCg2ywmZkv+3c7vsYZfivcfKhMh8kRxCrONM=
github.com/vdemeester/shakers v0.1.0/go.mod h1:IZ1HHynUOQt32iQ3rvAeVddXLd19h/6LWiKsh9RZtAQ=
github.com/vulcand/oxy v1.0.0 h1:7vL5/pjDFzHGbtBEhmlHITUi6KLH4xXTDF33/wrdRKw=
@@ -537,6 +553,8 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -563,6 +581,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -574,6 +593,8 @@ golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -18,6 +18,8 @@ import (
"github.com/stretchr/testify/require"
)
func Bool(v bool) *bool { return &v }
func TestHandler_HTTP(t *testing.T) {
type expected struct {
statusCode int
@@ -267,6 +269,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@@ -283,6 +286,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@@ -351,6 +355,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@@ -367,6 +372,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@@ -383,6 +389,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.3",
@@ -412,6 +419,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@@ -429,6 +437,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@@ -459,6 +468,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@@ -476,6 +486,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@@ -506,6 +517,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@@ -534,6 +546,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",

View File

@@ -38,6 +38,7 @@ func TestHandler_RawData(t *testing.T) {
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",

View File

@@ -65,7 +65,7 @@
"url": "http://127.0.0.1"
}
],
"passHostHeader": false
"passHostHeader": true
},
"status": "enabled",
"usedBy": [

View File

@@ -1,6 +1,6 @@
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.1"

View File

@@ -1,7 +1,7 @@
[
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.2"

View File

@@ -1,7 +1,7 @@
[
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.1"

View File

@@ -1,7 +1,7 @@
[
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.2"

View File

@@ -1,7 +1,7 @@
[
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.1"
@@ -22,7 +22,7 @@
},
{
"loadBalancer": {
"passHostHeader": false,
"passHostHeader": true,
"servers": [
{
"url": "http://127.0.0.2"

View File

@@ -106,7 +106,7 @@ type ServersLoadBalancer struct {
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty"`
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
PassHostHeader *bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
ResponseForwarding *ResponseForwarding `json:"responseForwarding,omitempty" toml:"responseForwarding,omitempty" yaml:"responseForwarding,omitempty"`
}
@@ -129,7 +129,8 @@ func (l *ServersLoadBalancer) Mergeable(loadBalancer *ServersLoadBalancer) bool
// SetDefaults Default values for a ServersLoadBalancer.
func (l *ServersLoadBalancer) SetDefaults() {
l.PassHostHeader = true
defaultPassHostHeader := true
l.PassHostHeader = &defaultPassHostHeader
}
// +k8s:deepcopy-gen=true

View File

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

View File

@@ -1,6 +1,7 @@
package file
import (
"fmt"
"reflect"
"sort"
"strconv"
@@ -15,12 +16,15 @@ func decodeRawToNode(data map[string]interface{}, rootName string, filters ...st
}
vData := reflect.ValueOf(data)
decodeRaw(root, vData, filters...)
err := decodeRaw(root, vData, filters...)
if err != nil {
return nil, err
}
return root, nil
}
func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) error {
sortedKeys := sortKeys(vData, filters)
for _, key := range sortedKeys {
@@ -38,7 +42,11 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
case reflect.Bool:
fallthrough
case reflect.String:
child.Value = getSimpleValue(value)
value, err := getSimpleValue(value)
if err != nil {
return err
}
child.Value = value
case reflect.Slice:
var values []string
@@ -63,40 +71,52 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
}
child.Children = append(child.Children, ch)
decodeRaw(ch, sValue)
err := decodeRaw(ch, sValue)
if err != nil {
return err
}
} else {
values = append(values, getSimpleValue(sValue))
val, err := getSimpleValue(sValue)
if err != nil {
return err
}
values = append(values, val)
}
default:
panic("Unsupported slice type: " + item.Kind().String())
return fmt.Errorf("field %s uses unsupported slice type: %s", child.Name, item.Kind().String())
}
}
child.Value = strings.Join(values, ",")
case reflect.Map:
decodeRaw(child, value)
err := decodeRaw(child, value)
if err != nil {
return err
}
default:
panic("Unsupported type: " + value.Kind().String())
return fmt.Errorf("field %s uses unsupported type: %s", child.Name, value.Kind().String())
}
node.Children = append(node.Children, child)
}
return nil
}
func getSimpleValue(item reflect.Value) string {
func getSimpleValue(item reflect.Value) (string, error) {
switch item.Kind() {
case reflect.String:
return item.String()
return item.String(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(item.Int(), 10)
return strconv.FormatInt(item.Int(), 10), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(item.Uint(), 10)
return strconv.FormatUint(item.Uint(), 10), nil
case reflect.Float32, reflect.Float64:
return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000")
return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000"), nil
case reflect.Bool:
return strconv.FormatBool(item.Bool())
return strconv.FormatBool(item.Bool()), nil
default:
panic("Unsupported Simple value type: " + item.Kind().String())
return "", fmt.Errorf("unsupported simple value type: %s", item.Kind().String())
}
}

View File

@@ -538,3 +538,27 @@ func Test_decodeRawToNode(t *testing.T) {
})
}
}
func Test_decodeRawToNode_errors(t *testing.T) {
testCases := []struct {
desc string
data map[string]interface{}
}{
{
desc: "invalid type",
data: map[string]interface{}{
"foo": struct{}{},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
_, err := decodeRawToNode(test.data, parser.DefaultRootName)
require.Error(t, err)
})
}
}

View File

@@ -544,7 +544,7 @@ func TestDecodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: true,
PassHostHeader: func(v bool) *bool { return &v }(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: "foobar",
},
@@ -570,7 +570,7 @@ func TestDecodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: true,
PassHostHeader: func(v bool) *bool { return &v }(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: "foobar",
},
@@ -946,7 +946,7 @@ func TestEncodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: true,
PassHostHeader: func(v bool) *bool { return &v }(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: "foobar",
},
@@ -972,7 +972,7 @@ func TestEncodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: true,
PassHostHeader: func(v bool) *bool { return &v }(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: "foobar",
},

View File

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

View File

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

View File

@@ -33,13 +33,14 @@ func TestJobBackOff(t *testing.T) {
// Assert that the next backoff falls in the expected range.
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
if i < 3 || i == 8 {
time.Sleep(2 * time.Second)
}
var actualInterval = exp.NextBackOff()
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
t.Error("error")
}
// assertEquals(t, expected, exp.currentInterval)
}
}

View File

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

View File

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

View File

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

View File

@@ -33,5 +33,7 @@ func (r *responseRecorder) CloseNotify() <-chan bool {
// Flush sends any buffered data to the client.
func (r *responseRecorder) Flush() {
r.ResponseWriter.(http.Flusher).Flush()
if f, ok := r.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}

View File

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

View File

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

View File

@@ -13,7 +13,8 @@ import (
"github.com/stretchr/testify/require"
)
func Int(v int) *int { return &v }
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func TestDefaultRule(t *testing.T) {
testCases := []struct {
@@ -64,7 +65,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -113,7 +114,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -164,7 +165,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -208,7 +209,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -252,7 +253,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -301,7 +302,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -384,7 +385,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -452,7 +453,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Test2": {
@@ -462,7 +463,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -531,7 +532,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -581,7 +582,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -633,7 +634,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -677,7 +678,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -734,7 +735,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -781,7 +782,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Service2": {
@@ -791,7 +792,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -842,7 +843,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1052,7 +1053,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1101,7 +1102,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1193,7 +1194,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1266,7 +1267,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1361,7 +1362,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1429,7 +1430,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1519,7 +1520,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1592,7 +1593,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1655,7 +1656,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Test2": {
@@ -1665,7 +1666,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1715,7 +1716,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1766,7 +1767,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "h2c://127.0.0.1:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1812,7 +1813,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Service2": {
@@ -1822,7 +1823,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -2037,7 +2038,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -2098,7 +2099,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -2348,7 +2349,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},

View File

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

View File

@@ -233,11 +233,11 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
var result []*v1alpha1.Middleware
for ns, factory := range c.factoriesCrd {
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector)
middlewares, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector)
if err != nil {
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
log.Errorf("Failed to list middlewares in namespace %s: %s", ns, err)
}
result = append(result, ings...)
result = append(result, middlewares...)
}
return result

View File

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

View File

@@ -164,8 +164,11 @@ func createLoadBalancerServerHTTP(client Client, namespace string, service v1alp
lb.SetDefaults()
lb.Servers = servers
if service.PassHostHeader != nil {
lb.PassHostHeader = *service.PassHostHeader
lb.PassHostHeader = service.PassHostHeader
if lb.PassHostHeader == nil {
passHostHeader := true
lb.PassHostHeader = &passHostHeader
}
lb.ResponseForwarding = service.ResponseForwarding
@@ -206,8 +209,13 @@ func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynam
var servers []dynamic.Server
if service.Spec.Type == corev1.ServiceTypeExternalName {
protocol := "http"
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
protocol = "https"
}
servers = append(servers, dynamic.Server{
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
})
} else {
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)

View File

@@ -12,7 +12,8 @@ import (
var _ provider.Provider = (*Provider)(nil)
func Int(v int) *int { return &v }
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func TestLoadIngressRouteTCPs(t *testing.T) {
testCases := []struct {
@@ -737,7 +738,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -786,7 +787,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -836,7 +837,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -878,7 +879,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"default-test.route-77c62dfe9517144aeeaa": {
@@ -891,7 +892,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -943,7 +944,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
@@ -956,7 +957,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1007,7 +1008,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"default-test.route-77c62dfe9517144aeeaa-whoami2-8080": {
@@ -1020,7 +1021,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1132,7 +1133,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1190,7 +1191,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1248,7 +1249,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1305,7 +1306,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1351,7 +1352,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1397,7 +1398,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1435,7 +1436,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1472,7 +1473,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "https://10.10.0.6:8443",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1509,7 +1510,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "https://10.10.0.8:8443",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1584,7 +1585,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1620,7 +1621,7 @@ func TestLoadIngressRoutes(t *testing.T) {
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: false,
PassHostHeader: Bool(false),
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: "10s"},
},
},

View File

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

View File

@@ -19,6 +19,8 @@ import (
var _ provider.Provider = (*Provider)(nil)
func Bool(v bool) *bool { return &v }
func TestLoadConfigurationFromIngresses(t *testing.T) {
testCases := []struct {
desc string
@@ -51,7 +53,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -85,7 +87,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -119,7 +121,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -149,7 +151,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -178,7 +180,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-example-com-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.11.0.1:80",
@@ -209,7 +211,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -243,7 +245,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -277,7 +279,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -318,7 +320,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -363,7 +365,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -376,7 +378,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"testing-service2-8082": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.2:8080",
@@ -420,7 +422,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"/": {
"default-router": {
Rule: "PathPrefix(`/`)",
Service: "default-backend",
Priority: math.MinInt32,
@@ -429,7 +431,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"default-backend": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
@@ -459,7 +461,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8089",
@@ -489,7 +491,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8089",
@@ -519,7 +521,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8089",
@@ -553,7 +555,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8089",
@@ -566,7 +568,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"testing-service1-carotte": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8090",
@@ -600,7 +602,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8089",
@@ -613,7 +615,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"toto-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.11.0.1:8089",
@@ -665,7 +667,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://traefik.wtf:8080",
@@ -697,7 +699,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-example-com-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.11.0.1:80",
@@ -734,7 +736,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "https://10.10.0.1:8443",
@@ -764,7 +766,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "https://10.10.0.1:8443",
@@ -795,7 +797,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "https://10.10.0.1:8443",
@@ -817,7 +819,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"/": {
"default-router": {
Rule: "PathPrefix(`/`)",
Service: "default-backend",
Priority: math.MinInt32,
@@ -826,7 +828,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"default-backend": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.30.0.1:8080",
@@ -856,7 +858,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: true,
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",

View File

@@ -11,7 +11,8 @@ import (
"github.com/stretchr/testify/require"
)
func Int(v int) *int { return &v }
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func TestGetConfigurationAPIErrors(t *testing.T) {
fakeClient := newFakeClient(true, marathon.Applications{})
@@ -64,7 +65,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -118,7 +119,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -164,7 +165,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -211,7 +212,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:8081",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -266,7 +267,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:8083",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -308,7 +309,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
"bar": {LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
@@ -316,7 +317,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:8081",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -354,7 +355,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:81",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -390,7 +391,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
}},
},
},
@@ -428,7 +429,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -459,7 +460,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -503,7 +504,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -537,7 +538,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Service2": {
@@ -547,7 +548,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -639,7 +640,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"app2": {
@@ -649,7 +650,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -696,7 +697,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"app2": {
@@ -706,7 +707,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -744,7 +745,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"app2": {
@@ -754,7 +755,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -802,7 +803,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -840,7 +841,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"app2": {
@@ -850,7 +851,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -887,7 +888,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -925,7 +926,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "h2c://localhost:90",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -958,7 +959,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Service2": {
@@ -968,7 +969,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:8080",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1133,7 +1134,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1171,7 +1172,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1208,7 +1209,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -1417,7 +1418,7 @@ func TestBuildConfiguration(t *testing.T) {
URL: "http://localhost:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},

View File

@@ -9,7 +9,8 @@ import (
"github.com/stretchr/testify/require"
)
func Int(v int) *int { return &v }
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func Test_buildConfiguration(t *testing.T) {
testCases := []struct {
@@ -51,7 +52,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -103,7 +104,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Test2": {
@@ -113,7 +114,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -168,7 +169,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
"Test2": {
@@ -178,7 +179,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://128.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -222,7 +223,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -310,7 +311,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -380,7 +381,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -433,7 +434,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -475,7 +476,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},
@@ -667,7 +668,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: true,
PassHostHeader: Bool(true),
},
},
},

View File

@@ -12,6 +12,7 @@ import (
func TestNewPoolContext(t *testing.T) {
type testKeyType string
testKey := testKeyType("test")
ctx := context.WithValue(context.Background(), testKey, "test")

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ const StatusClientClosedRequest = 499
// StatusClientClosedRequestText non-standard HTTP status for client disconnection
const StatusClientClosedRequestText = "Client Closed Request"
func buildProxy(passHostHeader bool, responseForwarding *dynamic.ResponseForwarding, defaultRoundTripper http.RoundTripper, bufferPool httputil.BufferPool, responseModifier func(*http.Response) error) (http.Handler, error) {
func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwarding, defaultRoundTripper http.RoundTripper, bufferPool httputil.BufferPool, responseModifier func(*http.Response) error) (http.Handler, error) {
var flushInterval types.Duration
if responseForwarding != nil {
err := flushInterval.Set(responseForwarding.FlushInterval)
@@ -53,7 +53,7 @@ func buildProxy(passHostHeader bool, responseForwarding *dynamic.ResponseForward
outReq.ProtoMinor = 1
// Do not pass client Host header unless optsetter PassHostHeader is set.
if !passHostHeader {
if passHostHeader != nil && !*passHostHeader {
outReq.Host = outReq.URL.Host
}

View File

@@ -28,7 +28,7 @@ func BenchmarkProxy(b *testing.B) {
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)
pool := newBufferPool()
handler, _ := buildProxy(false, nil, &staticTransport{res}, pool, nil)
handler, _ := buildProxy(Bool(false), nil, &staticTransport{res}, pool, nil)
b.ReportAllocs()
for i := 0; i < b.N; i++ {

View File

@@ -17,8 +17,10 @@ import (
"golang.org/x/net/websocket"
)
func Bool(v bool) *bool { return &v }
func TestWebSocketTCPClose(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
errChan := make(chan error, 1)
@@ -57,7 +59,7 @@ func TestWebSocketTCPClose(t *testing.T) {
}
func TestWebSocketPingPong(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
@@ -123,7 +125,7 @@ func TestWebSocketPingPong(t *testing.T) {
}
func TestWebSocketEcho(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
mux := http.NewServeMux()
@@ -189,7 +191,7 @@ func TestWebSocketPassHost(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
f, err := buildProxy(test.passHost, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(test.passHost), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
@@ -248,7 +250,7 @@ func TestWebSocketPassHost(t *testing.T) {
}
func TestWebSocketServerWithoutCheckOrigin(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
upgrader := gorillawebsocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
@@ -289,7 +291,7 @@ func TestWebSocketServerWithoutCheckOrigin(t *testing.T) {
}
func TestWebSocketRequestWithOrigin(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
upgrader := gorillawebsocket.Upgrader{}
@@ -335,7 +337,7 @@ func TestWebSocketRequestWithOrigin(t *testing.T) {
}
func TestWebSocketRequestWithQueryParams(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
upgrader := gorillawebsocket.Upgrader{}
@@ -375,7 +377,7 @@ func TestWebSocketRequestWithQueryParams(t *testing.T) {
}
func TestWebSocketRequestWithHeadersInResponseWriter(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
mux := http.NewServeMux()
@@ -407,7 +409,7 @@ func TestWebSocketRequestWithHeadersInResponseWriter(t *testing.T) {
}
func TestWebSocketRequestWithEncodedChar(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
upgrader := gorillawebsocket.Upgrader{}
@@ -447,7 +449,7 @@ func TestWebSocketRequestWithEncodedChar(t *testing.T) {
}
func TestWebSocketUpgradeFailed(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
mux := http.NewServeMux()
@@ -497,7 +499,7 @@ func TestWebSocketUpgradeFailed(t *testing.T) {
}
func TestForwardsWebsocketTraffic(t *testing.T) {
f, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
f, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
mux := http.NewServeMux()
@@ -553,7 +555,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
srv := createTLSWebsocketServer()
defer srv.Close()
forwarderWithoutTLSConfig, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
forwarderWithoutTLSConfig, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
proxyWithoutTLSConfig := createProxyWithForwarder(t, forwarderWithoutTLSConfig, srv.URL)
@@ -572,7 +574,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
transport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
forwarderWithTLSConfig, err := buildProxy(true, nil, transport, nil, nil)
forwarderWithTLSConfig, err := buildProxy(Bool(true), nil, transport, nil, nil)
require.NoError(t, err)
proxyWithTLSConfig := createProxyWithForwarder(t, forwarderWithTLSConfig, srv.URL)
@@ -591,7 +593,7 @@ func TestWebSocketTransferTLSConfig(t *testing.T) {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
forwarderWithTLSConfigFromDefaultTransport, err := buildProxy(true, nil, http.DefaultTransport, nil, nil)
forwarderWithTLSConfigFromDefaultTransport, err := buildProxy(Bool(true), nil, http.DefaultTransport, nil, nil)
require.NoError(t, err)
proxyWithTLSConfigFromDefaultTransport := createProxyWithForwarder(t, forwarderWithTLSConfigFromDefaultTransport, srv.URL)

View File

@@ -176,6 +176,11 @@ func (m *Manager) getLoadBalancerServiceHandler(
service *dynamic.ServersLoadBalancer,
responseModifier func(*http.Response) error,
) (http.Handler, error) {
if service.PassHostHeader == nil {
defaultPassHostHeader := true
service.PassHostHeader = &defaultPassHostHeader
}
fwd, err := buildProxy(service.PassHostHeader, service.ResponseForwarding, m.defaultRoundTripper, m.bufferPool, responseModifier)
if err != nil {
return nil, err

View File

@@ -221,7 +221,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
serviceName: "test",
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
PassHostHeader: true,
PassHostHeader: func(v bool) *bool { return &v }(true),
Servers: []dynamic.Server{
{
URL: serverPassHost.URL,
@@ -239,7 +239,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
desc: "PassHost doesn't passe the host instead of the IP",
serviceName: "test",
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
PassHostHeader: Bool(false),
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
Servers: []dynamic.Server{
{
URL: serverPassHostFalse.URL,

View File

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

View File

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

View File

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

View File

@@ -91,10 +91,7 @@ func (t *Tracing) Extract(format interface{}, carrier interface{}) (opentracing.
// IsEnabled determines if tracing was successfully activated.
func (t *Tracing) IsEnabled() bool {
if t == nil || t.tracer == nil {
return false
}
return true
return t != nil && t.tracer != nil
}
// Close tracer
@@ -169,9 +166,7 @@ func StartSpan(r *http.Request, operationName string, spanKind ext.SpanKindEnum,
}
r = r.WithContext(ctx)
return span, r, func() {
span.Finish()
}
return span, r, func() { span.Finish() }
}
// SetError flags the span associated with this request as in error.

View File

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

View File

@@ -2,8 +2,7 @@
SCRIPT_DIR="$( cd "$( dirname "${0}" )" && pwd -P)"
files=()
while IFS='' read -r line; do files+=("$line"); done < <(git ls-files "${SCRIPT_DIR}"/../'docs/*.md' "${SCRIPT_DIR}"/../*.md)
while IFS='' read -r line; do files+=("$line"); done < <(git ls-files "${SCRIPT_DIR}"/../'docs/*.md' "${SCRIPT_DIR}"/../*.md | grep -v "CHANGELOG.md")
errors=()
for f in "${files[@]}"; do

View File

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

View File

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

View File

@@ -54,37 +54,8 @@
</div>
</q-card-section>
<q-separator v-if="data.weighted && data.weighted.sticky" />
<q-card-section v-if="data.weighted && data.weighted.sticky" >
<div class="row items-start no-wrap">
<div class="text-subtitle1">Sticky: Cookie</div>
</div>
</q-card-section>
<q-card-section v-if="data.weighted && data.weighted.sticky" >
<div class="row items-start no-wrap">
<div class="col" v-if="data.weighted.sticky.cookie && data.weighted.sticky.cookie.name">
<div class="text-subtitle2">NAME</div>
<q-chip
dense
class="app-chip app-chip-entry-points">
{{ data.weighted.sticky.cookie.name }}
</q-chip>
</div>
</div>
</q-card-section>
<q-card-section v-if="data.weighted && data.weighted.sticky" >
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">SECURE</div>
<boolean-state :value="data.weighted.sticky.cookie.secure"/>
</div>
<div class="col">
<div class="text-subtitle2">HTTP Only</div>
<boolean-state :value="data.weighted.sticky.cookie.httpOnly"/>
</div>
</div>
</q-card-section>
<q-separator v-if="sticky" />
<StickyServiceDetails v-if="sticky" :sticky="sticky" :dense="dense"/>
</q-scroll-area>
</q-card>
</template>
@@ -92,17 +63,30 @@
<script>
import AvatarState from './AvatarState'
import BooleanState from './BooleanState'
import StickyServiceDetails from './StickyServiceDetails'
export default {
name: 'PanelServiceDetails',
props: ['data', 'dense'],
components: {
BooleanState,
AvatarState
AvatarState,
StickyServiceDetails
},
computed: {
isDense () {
return this.dense !== undefined
},
sticky () {
if (this.data.weighted && this.data.weighted.sticky) {
return this.data.weighted.sticky
}
if (this.data.loadBalancer && this.data.loadBalancer.sticky) {
return this.data.loadBalancer.sticky
}
return null
}
},
filters: {

View File

@@ -0,0 +1,68 @@
<template>
<div>
<q-card-section>
<div class="row items-start no-wrap">
<div class="text-subtitle1">Sticky: Cookie </div>
</div>
</q-card-section>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col" v-if="sticky.cookie && sticky.cookie.name">
<div class="text-subtitle2">NAME</div>
<q-chip
dense
class="app-chip app-chip-entry-points">
{{ sticky.cookie.name }}
</q-chip>
</div>
</div>
</q-card-section>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">SECURE</div>
<boolean-state :value="sticky.cookie.secure"/>
</div>
<div class="col">
<div class="text-subtitle2">HTTP Only</div>
<boolean-state :value="sticky.cookie.httpOnly"/>
</div>
</div>
</q-card-section>
</div>
</template>
<script>
import BooleanState from './BooleanState'
export default {
name: 'StickyServiceDetails',
components: {
BooleanState
},
props: ['sticky', 'dense']
}
</script>
<style scoped lang="scss">
@import "../../css/sass/variables";
.q-card__section {
padding: 24px;
+ .q-card__section {
padding-top: 0;
}
}
.text-subtitle2 {
font-size: 11px;
color: $app-text-grey;
line-height: 16px;
margin-bottom: 4px;
text-align: left;
letter-spacing: 2px;
font-weight: 600;
text-transform: uppercase;
}
</style>