mirror of
https://github.com/containous/traefik.git
synced 2025-09-08 13:44:22 +03:00
Compare commits
96 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fc52d1cfba | ||
|
fdf2a68a11 | ||
|
e63db782c1 | ||
|
a6c6127e33 | ||
|
bbbc18fd84 | ||
|
2c7f6e4def | ||
|
ff16925f63 | ||
|
0b7aaa3643 | ||
|
45f52ca29c | ||
|
fae2d93525 | ||
|
25b74ce1f3 | ||
|
a3df5b9a94 | ||
|
04f0ebf776 | ||
|
0e97a3becd | ||
|
77a0cef9ce | ||
|
143e9b6f9c | ||
|
06dcf8d8aa | ||
|
c315b4e064 | ||
|
d7f517fbf5 | ||
|
b10cb84f33 | ||
|
a55f0cabdd | ||
|
d73c7ccf50 | ||
|
2b35397169 | ||
|
416c367778 | ||
|
a20e90aa17 | ||
|
d698eba1e7 | ||
|
fe8e9414cf | ||
|
3350b56057 | ||
|
4d71f682b3 | ||
|
607cda779d | ||
|
b61de07ca0 | ||
|
295ed76a1a | ||
|
8da051789f | ||
|
30e0778ed2 | ||
|
7b1a256546 | ||
|
cc4879fb76 | ||
|
7c54a45950 | ||
|
dabf69abc7 | ||
|
8d3d5c068c | ||
|
8d827f98da | ||
|
e5e46bf4ed | ||
|
9f32292473 | ||
|
b0f7b71453 | ||
|
c0c540dc09 | ||
|
7694ff1761 | ||
|
0d902671e5 | ||
|
fb90a7889a | ||
|
48c73d6a34 | ||
|
12e462f383 | ||
|
b7fe55b6be | ||
|
a1270d6cc7 | ||
|
f874c389bd | ||
|
8c5846c478 | ||
|
dce807a329 | ||
|
42ec4e4e98 | ||
|
635e3fb9a8 | ||
|
04257afab7 | ||
|
b673969a0f | ||
|
c52c40f061 | ||
|
abdb5cc6cb | ||
|
4a6817c64b | ||
|
328611c619 | ||
|
f12c27aa7c | ||
|
e22c62baba | ||
|
efcaf64a43 | ||
|
f120301bc8 | ||
|
4da63c9237 | ||
|
97294df84f | ||
|
de42fc10b5 | ||
|
e5c6b0d4ea | ||
|
7c7ca7ef2b | ||
|
a813d32c53 | ||
|
2f18e20cb0 | ||
|
2ce2d63bda | ||
|
367e797d5f | ||
|
4fcf7bf2de | ||
|
e1d51b51f2 | ||
|
40b4032ea0 | ||
|
756aa82aa9 | ||
|
fe5a4a26f8 | ||
|
2171cb7f3d | ||
|
f55a09862e | ||
|
d0b21efd36 | ||
|
daf4258472 | ||
|
619bc95b2b | ||
|
76c2fa6d9a | ||
|
77bf3ac6ce | ||
|
0d7761f097 | ||
|
6c08d0b20b | ||
|
148400ae0a | ||
|
ac1657d86e | ||
|
332c314d53 | ||
|
5c8d386881 | ||
|
6f749c6414 | ||
|
a6b6e1d101 | ||
|
aa68cc2e63 |
@@ -49,6 +49,11 @@
|
||||
"wsl", # Too strict
|
||||
"gomnd", # Too strict
|
||||
"stylecheck", # skip because report issues related to some generated files.
|
||||
"testpackage", # Too strict
|
||||
"goerr113", # Too strict
|
||||
"nestif", # Too many false-positive.
|
||||
"noctx", # Too strict
|
||||
"exhaustive", # Too strict
|
||||
]
|
||||
|
||||
[issues]
|
||||
@@ -62,7 +67,7 @@
|
||||
]
|
||||
[[issues.exclude-rules]]
|
||||
path = "(.+)_test.go"
|
||||
linters = ["goconst", "funlen"]
|
||||
linters = ["goconst", "funlen", "godot"]
|
||||
[[issues.exclude-rules]]
|
||||
path = "integration/.+_test.go"
|
||||
text = "Error return value of `cmd\\.Process\\.Kill` is not checked"
|
||||
@@ -105,3 +110,6 @@
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/tracing/tracing.go"
|
||||
text = "printf-like formatting function 'SetErrorWithEvent' should be named 'SetErrorWithEventf'"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/log/deprecated.go"
|
||||
linters = ["godot"]
|
||||
|
132
CHANGELOG.md
132
CHANGELOG.md
@@ -1,3 +1,135 @@
|
||||
## [v2.2.8](https://github.com/containous/traefik/tree/v2.2.8) (2020-07-28)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.7...v2.2.8)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[webui]** fix: clean X-Forwarded-Prefix header for the dashboard. ([#7109](https://github.com/containous/traefik/pull/7109) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[docker]** spelling(docs/content/routing/providers/docker.md) ([#7101](https://github.com/containous/traefik/pull/7101) by [szczot3k](https://github.com/szczot3k))
|
||||
- **[k8s]** doc: add name of used key for kubernetes client auth ([#7068](https://github.com/containous/traefik/pull/7068) by [smueller18](https://github.com/smueller18))
|
||||
|
||||
## [v2.2.7](https://github.com/containous/traefik/tree/v2.2.7) (2020-07-20)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.6...v2.2.7)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[server,tls]** fix: drop host port to compare with SNI. ([#7071](https://github.com/containous/traefik/pull/7071) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v2.2.6](https://github.com/containous/traefik/tree/v2.2.6) (2020-07-17)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.5...v2.2.6)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[logs]** fix: access logs header names filtering is case insensitive ([#6900](https://github.com/containous/traefik/pull/6900) by [mjeanroy](https://github.com/mjeanroy))
|
||||
- **[provider]** Get Entrypoints Port Address without protocol for redirect ([#7047](https://github.com/containous/traefik/pull/7047) by [SantoDE](https://github.com/SantoDE))
|
||||
- **[tls]** Fix domain fronting ([#7064](https://github.com/containous/traefik/pull/7064) by [juliens](https://github.com/juliens))
|
||||
|
||||
**Documentation:**
|
||||
- fix: documentation references. ([#7049](https://github.com/containous/traefik/pull/7049) by [ldez](https://github.com/ldez))
|
||||
- Add example for entrypoint on one ip address ([#6483](https://github.com/containous/traefik/pull/6483) by [SimonHeimberg](https://github.com/SimonHeimberg))
|
||||
|
||||
## [v2.2.5](https://github.com/containous/traefik/tree/v2.2.5) (2020-07-13)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.4...v2.2.5)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[k8s,k8s/crd]** fix k8s crd to read contentType middleware into dynamic config ([#7034](https://github.com/containous/traefik/pull/7034) by [johnpekcan](https://github.com/johnpekcan))
|
||||
- **[rules,server,tls]** Revert domain fronting fix ([#7039](https://github.com/containous/traefik/pull/7039) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[tls]** Fix default value for InsecureSNI when global is not set ([#7037](https://github.com/containous/traefik/pull/7037) by [juliens](https://github.com/juliens))
|
||||
|
||||
## [v2.2.4](https://github.com/containous/traefik/tree/v2.2.4) (2020-07-10)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.3...v2.2.4)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[tls]** Change the default value of insecureSNI ([#7027](https://github.com/containous/traefik/pull/7027) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
|
||||
## [v2.2.3](https://github.com/containous/traefik/tree/v2.2.3) (2020-07-09)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.2...v2.2.3)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[middleware]** Fix panic when using chain middleware. ([#7016](https://github.com/containous/traefik/pull/7016) by [juliens](https://github.com/juliens))
|
||||
|
||||
## [v2.2.2](https://github.com/containous/traefik/tree/v2.2.2) (2020-07-08)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.1...v2.2.2)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Update go-acme/lego to v3.8.0 ([#6988](https://github.com/containous/traefik/pull/6988) by [ldez](https://github.com/ldez))
|
||||
- **[acme]** Fix triggering multiple concurrent requests to ACME ([#6939](https://github.com/containous/traefik/pull/6939) by [ddtmachado](https://github.com/ddtmachado))
|
||||
- **[acme]** Update go-acme/lego to v3.7.0 ([#6792](https://github.com/containous/traefik/pull/6792) by [ldez](https://github.com/ldez))
|
||||
- **[acme]** added required quotes to domains config ([#6867](https://github.com/containous/traefik/pull/6867) by [tompson](https://github.com/tompson))
|
||||
- **[authentication,logs,middleware]** Provide username in log data on auth failure ([#6827](https://github.com/containous/traefik/pull/6827) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[docker]** Use specified network for "container" network mode ([#6763](https://github.com/containous/traefik/pull/6763) by [bjeanes](https://github.com/bjeanes))
|
||||
- **[k8s,k8s/crd]** Remove checkStringQuoteValidity in loadIngressRouteConf ([#6775](https://github.com/containous/traefik/pull/6775) by [fefe982](https://github.com/fefe982))
|
||||
- **[middleware,websocket]** Fix wss in x-forwarded-proto ([#6752](https://github.com/containous/traefik/pull/6752) by [juliens](https://github.com/juliens))
|
||||
- **[middleware]** internal handlers: support for response modifiers ([#6750](https://github.com/containous/traefik/pull/6750) by [mpl](https://github.com/mpl))
|
||||
- **[middleware]** Fix ipv6 handling in redirect middleware ([#6902](https://github.com/containous/traefik/pull/6902) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[middleware]** refactor X-Forwarded-Proto ([#6863](https://github.com/containous/traefik/pull/6863) by [jcgruenhage](https://github.com/jcgruenhage))
|
||||
- **[provider]** Fix race condition issues with provided dynamic configuration ([#6979](https://github.com/containous/traefik/pull/6979) by [kevinpollet](https://github.com/kevinpollet))
|
||||
- **[rules,server,tls]** Disable domain fronting ([#7008](https://github.com/containous/traefik/pull/7008) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[udp]** Fix mem leak on UDP connections ([#6815](https://github.com/containous/traefik/pull/6815) by [ddtmachado](https://github.com/ddtmachado))
|
||||
- **[udp]** Avoid overwriting already received UDP messages ([#6797](https://github.com/containous/traefik/pull/6797) by [cbachert](https://github.com/cbachert))
|
||||
- **[webui]** Add missing accessControlAllowOrigin list to middleware view ([#6747](https://github.com/containous/traefik/pull/6747) by [barthez](https://github.com/barthez))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Fix doc url for Aurora DNS provider ([#6899](https://github.com/containous/traefik/pull/6899) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[acme]** Fix acme.md typo ([#6817](https://github.com/containous/traefik/pull/6817) by [juliocc](https://github.com/juliocc))
|
||||
- **[acme]** fix certResolver typo ([#6983](https://github.com/containous/traefik/pull/6983) by [DavidBadura](https://github.com/DavidBadura))
|
||||
- **[acme]** Fix statement about lego _FILE env var ([#6964](https://github.com/containous/traefik/pull/6964) by [solvaholic](https://github.com/solvaholic))
|
||||
- **[acme]** Improve acme CLI options in Let's Encrypt documentation ([#6762](https://github.com/containous/traefik/pull/6762) by [netoax](https://github.com/netoax))
|
||||
- **[docker]** fix a broken link on Docker plugins documentation ([#6908](https://github.com/containous/traefik/pull/6908) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- **[docker]** Fix healthcheck.interval in docs ([#6847](https://github.com/containous/traefik/pull/6847) by [OndrejIT](https://github.com/OndrejIT))
|
||||
- **[k8s,k8s/ingress]** Remove redundant paragraph in Kubernetes ingress documentation ([#6806](https://github.com/containous/traefik/pull/6806) by [lpfann](https://github.com/lpfann))
|
||||
- **[k8s,k8s/ingress]** Fix sticky cookie ingress annotation doc ([#6938](https://github.com/containous/traefik/pull/6938) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[k8s]** fixing typo in Provider KubernetesIngress at Routing documentation ([#6845](https://github.com/containous/traefik/pull/6845) by [sw360cab](https://github.com/sw360cab))
|
||||
- **[k8s]** Update kubernetes-crd.md ([#6878](https://github.com/containous/traefik/pull/6878) by [rherrick](https://github.com/rherrick))
|
||||
- **[logs]** Fixed incorrect logging parameter in documentation ([#6819](https://github.com/containous/traefik/pull/6819) by [cplewnia](https://github.com/cplewnia))
|
||||
- **[logs]** Use "headers" instead of "header" in access log docs ([#6836](https://github.com/containous/traefik/pull/6836) by [bradjones1](https://github.com/bradjones1))
|
||||
- **[middleware,k8s/crd]** Fix Headers middleware documentation, usage of proper bool ([#6928](https://github.com/containous/traefik/pull/6928) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[middleware]** Improve redirectScheme documentation ([#6769](https://github.com/containous/traefik/pull/6769) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[middleware]** Update basicauth.md ([#6967](https://github.com/containous/traefik/pull/6967) by [vitalets](https://github.com/vitalets))
|
||||
- Update Dashboard examples and move it after 'Router Rule' section ([#6874](https://github.com/containous/traefik/pull/6874) by [ddtmachado](https://github.com/ddtmachado))
|
||||
- Fix log field names in documentation ([#6952](https://github.com/containous/traefik/pull/6952) by [gysel](https://github.com/gysel))
|
||||
- Minor fix to Go templating documentation ([#6977](https://github.com/containous/traefik/pull/6977) by [PCM2](https://github.com/PCM2))
|
||||
- Add rtribotte to maintainers ([#6936](https://github.com/containous/traefik/pull/6936) by [emilevauge](https://github.com/emilevauge))
|
||||
- Update Copyright ([#6795](https://github.com/containous/traefik/pull/6795) by [mmatur](https://github.com/mmatur))
|
||||
- fix: dead link. ([#6876](https://github.com/containous/traefik/pull/6876) by [ldez](https://github.com/ldez))
|
||||
- Fix v1-> v2 migration: unify domain name in documentation example ([#6904](https://github.com/containous/traefik/pull/6904) by [sinacek](https://github.com/sinacek))
|
||||
|
||||
## [v2.2.1](https://github.com/containous/traefik/tree/v2.2.1) (2020-04-29)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.2.0...v2.2.1)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Update go-acme/lego to v3.6.0 ([#6727](https://github.com/containous/traefik/pull/6727) by [ldez](https://github.com/ldez))
|
||||
- **[consulcatalog]** Normalize default names for ConsulCatalog. ([#6593](https://github.com/containous/traefik/pull/6593) by [ldez](https://github.com/ldez))
|
||||
- **[internal]** Change the default priority on the router created by the redirect. ([#6588](https://github.com/containous/traefik/pull/6588) by [ldez](https://github.com/ldez))
|
||||
- **[k8s,k8s/ingress]** Delete an unnecessary warning log ([#6624](https://github.com/containous/traefik/pull/6624) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- **[middleware]** ratelimit: do not default to ipstrategy too early ([#6713](https://github.com/containous/traefik/pull/6713) by [mpl](https://github.com/mpl))
|
||||
- **[rancher,webui]** It's just the one TLS, actually. ([#6606](https://github.com/containous/traefik/pull/6606) by [RealOrangeOne](https://github.com/RealOrangeOne))
|
||||
- **[server]** Fix case-sensitive header Sec-Websocket-Version ([#6698](https://github.com/containous/traefik/pull/6698) by [tbrandstetter](https://github.com/tbrandstetter))
|
||||
- **[udp]** fix: consider UDP when checking for empty config ([#6683](https://github.com/containous/traefik/pull/6683) by [nrwiersma](https://github.com/nrwiersma))
|
||||
- **[websocket]** FIx wS heAder ([#6660](https://github.com/containous/traefik/pull/6660) by [mmatur](https://github.com/mmatur))
|
||||
- **[websocket]** Manage case for all Websocket headers ([#6705](https://github.com/containous/traefik/pull/6705) by [mmatur](https://github.com/mmatur))
|
||||
- **[webui]** Disable distribution of the WebUI as PWA ([#6717](https://github.com/containous/traefik/pull/6717) by [SantoDE](https://github.com/SantoDE))
|
||||
- **[webui]** Add polling for getOverview in toolbar ([#6611](https://github.com/containous/traefik/pull/6611) by [lukashass](https://github.com/lukashass))
|
||||
|
||||
**Documentation:**
|
||||
- **[api]** Fix documentation about api.insecure defaults ([#6671](https://github.com/containous/traefik/pull/6671) by [thisismydesign](https://github.com/thisismydesign))
|
||||
- **[docker,k8s,k8s/ingress,marathon,rancher,sticky-session]** fix: cookie documentation. ([#6745](https://github.com/containous/traefik/pull/6745) by [ldez](https://github.com/ldez))
|
||||
- **[file]** Edit code indentation for correct alignment ([#6691](https://github.com/containous/traefik/pull/6691) by [fbruetting](https://github.com/fbruetting))
|
||||
- **[healthcheck,k8s,k8s/crd]** Add note about health check in kubernetes ([#6647](https://github.com/containous/traefik/pull/6647) by [mmatur](https://github.com/mmatur))
|
||||
- **[k8s,k8s/crd]** docs: Update kubernetes-crd-resource.yml ([#6741](https://github.com/containous/traefik/pull/6741) by [rdxmb](https://github.com/rdxmb))
|
||||
- **[k8s,k8s/crd]** doc: improve CRD documentation. ([#6681](https://github.com/containous/traefik/pull/6681) by [ldez](https://github.com/ldez))
|
||||
- **[k8s/crd]** doc: add apiVersion for "kind: Middleware" ([#6734](https://github.com/containous/traefik/pull/6734) by [yuyicai](https://github.com/yuyicai))
|
||||
- **[k8s/helm]** Update the documentation for helm chart ([#6744](https://github.com/containous/traefik/pull/6744) by [mmatur](https://github.com/mmatur))
|
||||
- **[k8s]** Add sentence about the resource namespace and middleware ([#6719](https://github.com/containous/traefik/pull/6719) by [SantoDE](https://github.com/SantoDE))
|
||||
- **[kv]** fix KV service docs for http:url and tcp:address ([#6720](https://github.com/containous/traefik/pull/6720) by [bryfry](https://github.com/bryfry))
|
||||
- **[logs]** Add Access log chapter for migration v1->v2 ([#6689](https://github.com/containous/traefik/pull/6689) by [MartinKoerner](https://github.com/MartinKoerner))
|
||||
- **[middleware]** Update headers.md ([#6675](https://github.com/containous/traefik/pull/6675) by [jamct](https://github.com/jamct))
|
||||
- **[middleware]** Doc middleware compress content type ([#6738](https://github.com/containous/traefik/pull/6738) by [rtribotte](https://github.com/rtribotte))
|
||||
- **[tracing]** Add link to tracing with elastic ([#6673](https://github.com/containous/traefik/pull/6673) by [collinmutembei](https://github.com/collinmutembei))
|
||||
- Added missing text `a yaml file` in Configuration ([#6663](https://github.com/containous/traefik/pull/6663) by [fsoedjede](https://github.com/fsoedjede))
|
||||
- Fix typos in the documentation ([#6650](https://github.com/containous/traefik/pull/6650) by [SuperSandro2000](https://github.com/SuperSandro2000))
|
||||
- Fix documentation ([#6648](https://github.com/containous/traefik/pull/6648) by [mmatur](https://github.com/mmatur))
|
||||
- Fix bad address syntax in Global HTTP to HTTPS redirection v2 TOML ([#6619](https://github.com/containous/traefik/pull/6619) by [Beetix](https://github.com/Beetix))
|
||||
- Doc Fix for 2.2 Redirects ([#6595](https://github.com/containous/traefik/pull/6595) by [ajschmidt8](https://github.com/ajschmidt8))
|
||||
|
||||
## [v2.2.0](https://github.com/containous/traefik/tree/v2.2.0) (2020-03-25)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v2.1.0-rc1...v2.2.0)
|
||||
|
||||
|
2
Makefile
2
Makefile
@@ -32,7 +32,7 @@ TRAEFIK_ENVS := \
|
||||
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
|
||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
DOCKER_NON_INTERACTIVE ?= false
|
||||
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK := docker run --add-host=host.docker.internal:127.0.0.1 $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -i) $(DOCKER_RUN_OPTS)
|
||||
|
||||
PRE_TARGET ?= build-dev-image
|
||||
|
@@ -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.23.8
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.28.0
|
||||
|
||||
# Download misspell binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ContextWithSignal creates a context canceled when SIGINT or SIGTERM are notified
|
||||
// ContextWithSignal creates a context canceled when SIGINT or SIGTERM are notified.
|
||||
func ContextWithSignal(ctx context.Context) context.Context {
|
||||
newCtx, cancel := context.WithCancel(ctx)
|
||||
signals := make(chan os.Signal)
|
||||
|
@@ -45,7 +45,7 @@ func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Do try to do a healthcheck
|
||||
// Do try to do a healthcheck.
|
||||
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
|
||||
if staticConfiguration.Ping == nil {
|
||||
return nil, errors.New("please enable `ping` to use health check")
|
||||
|
@@ -274,7 +274,7 @@ func switchRouter(routerFactory *server.RouterFactory, acmeProviders []*acme.Pro
|
||||
}
|
||||
}
|
||||
|
||||
// initACMEProvider creates an acme provider from the ACME part of globalConfiguration
|
||||
// initACMEProvider creates an acme provider from the ACME part of globalConfiguration.
|
||||
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager) []*acme.Provider {
|
||||
challengeStore := acme.NewLocalChallengeStore()
|
||||
localStores := map[string]*acme.LocalStore{}
|
||||
@@ -403,7 +403,7 @@ func configureLogging(staticConfiguration *static.Configuration) {
|
||||
if len(logFile) > 0 {
|
||||
dir := filepath.Dir(logFile)
|
||||
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
log.WithoutContext().Errorf("Failed to create log path %s: %s", dir, err)
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,7 @@ Go version: {{.GoVersion}}
|
||||
Built: {{.BuildTime}}
|
||||
OS/Arch: {{.Os}}/{{.Arch}}`
|
||||
|
||||
// NewCmd builds a new Version command
|
||||
// NewCmd builds a new Version command.
|
||||
func NewCmd() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "version",
|
||||
@@ -33,7 +33,7 @@ func NewCmd() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPrint write Printable version
|
||||
// GetPrint write Printable version.
|
||||
func GetPrint(wr io.Writer) error {
|
||||
tmpl, err := template.New("").Parse(versionTemplate)
|
||||
if err != nil {
|
||||
|
@@ -16,6 +16,7 @@
|
||||
* Gérald Croës [@geraldcroes](https://github.com/geraldcroes)
|
||||
* Jean-Baptiste Doumenjou [@jbdoumenjou](https://github.com/jbdoumenjou)
|
||||
* Mathieu Lonjaret [@mpl](https://github.com/mpl)
|
||||
* Romain Tribotté [@rtribotte](https://github.com/rtribotte)
|
||||
|
||||
## Contributions Daily Meeting
|
||||
|
||||
|
@@ -78,20 +78,53 @@ helm install traefik traefik/traefik
|
||||
The values are not (yet) documented, but are self-explanatory:
|
||||
you can look at the [default `values.yaml`](https://github.com/containous/traefik-helm-chart/blob/master/traefik/values.yaml) file to explore possibilities.
|
||||
|
||||
You can also set Traefik command line flags using `additionalArguments`.
|
||||
Example of installation with logging set to `DEBUG`:
|
||||
|
||||
```bash tab="Using Helm CLI"
|
||||
helm install --namespace=traefik-v2 \
|
||||
--set="logs.loglevel=DEBUG" \
|
||||
--set="additionalArguments={--log.level=DEBUG}" \
|
||||
traefik traefik/traefik
|
||||
```
|
||||
|
||||
```yml tab="With a custom values file"
|
||||
# File custom-values.yml
|
||||
## Install with "helm install --values=./custom-values.yml traefik traefik/traefik
|
||||
logs:
|
||||
loglevel: DEBUG
|
||||
additionalArguments:
|
||||
- "--log.level=DEBUG"
|
||||
```
|
||||
|
||||
### Exposing the Traefik dashboard
|
||||
|
||||
This HelmChart does not expose the Traefik dashboard by default, for security concerns.
|
||||
Thus, there are multiple ways to expose the dashboard.
|
||||
For instance, the dashboard access could be achieved through a port-forward :
|
||||
|
||||
```shell
|
||||
kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
|
||||
```
|
||||
|
||||
Accessible with the url: http://127.0.0.1:9000/dashboard/
|
||||
|
||||
Another way would be to apply your own configuration, for instance,
|
||||
by defining and applying an IngressRoute CRD (`kubectl apply -f dashboard.yaml`):
|
||||
|
||||
```yaml
|
||||
# dashboard.yaml
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dashboard
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`traefik.localhost`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
```
|
||||
|
||||
## Use the Binary Distribution
|
||||
|
||||
|
@@ -105,13 +105,13 @@ Please check the [configuration examples below](#configuration-examples) for mor
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesResolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
# used during the challenge
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
```
|
||||
|
||||
!!! important "Defining a certificates resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must [reference](../routing/routers/index.md#certresolver) it."
|
||||
@@ -181,7 +181,7 @@ when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encry
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.tlsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.tlschallenge=true
|
||||
```
|
||||
|
||||
### `httpChallenge`
|
||||
@@ -189,7 +189,7 @@ when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encry
|
||||
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI.
|
||||
|
||||
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72),
|
||||
when using the `HTTP-01` challenge, `certificatesResolvers.myresolver.acme.httpChallenge.entryPoint` must be reachable by Let's Encrypt through port 80.
|
||||
when using the `HTTP-01` challenge, `certificatesresolvers.myresolver.acme.httpchallenge.entrypoint` must be reachable by Let's Encrypt through port 80.
|
||||
|
||||
??? example "Using an EntryPoint Called web for the `httpChallenge`"
|
||||
|
||||
@@ -224,10 +224,10 @@ when using the `HTTP-01` challenge, `certificatesResolvers.myresolver.acme.httpC
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
```
|
||||
|
||||
!!! info ""
|
||||
@@ -261,8 +261,8 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.provider=digitalocean
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.provider=digitalocean
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -275,24 +275,29 @@ Here is a list of supported `providers`, that can automate the DNS verification,
|
||||
along with the required environment variables and their [wildcard & root domain support](#wildcard-domains).
|
||||
Do not hesitate to complete it.
|
||||
|
||||
Every lego environment variable can be overridden by their respective `_FILE` counterpart, which should have a filepath to a file that contains the secret as its value.
|
||||
Many lego environment variables can be overridden by their respective `_FILE` counterpart, which should have a filepath to a file that contains the secret as its value.
|
||||
For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used to provide a Cloudflare API email address as a Docker secret named `traefik_cf-api-email`.
|
||||
|
||||
For complete details, refer to your provider's _Additional configuration_ link.
|
||||
|
||||
| Provider Name | Provider Code | Environment Variables | |
|
||||
|-------------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) |
|
||||
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) |
|
||||
| [ArvanCloud](https://arvancloud.com) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) |
|
||||
| [Auroradns](https://www.pcextreme.com/dns-health-checks) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) |
|
||||
| [Autodns](https://www.internetx.com/domains/autodns/) | `autodns` | `AUTODNS_API_USER`, `AUTODNS_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/autodns) |
|
||||
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | [Additional configuration](https://go-acme.github.io/lego/dns/azure) |
|
||||
| [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) |
|
||||
| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) |
|
||||
| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) |
|
||||
| [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` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [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) |
|
||||
| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) |
|
||||
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
|
||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
|
||||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
|
||||
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) |
|
||||
@@ -311,6 +316,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) |
|
||||
| [GoDaddy](https://godaddy.com/) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) |
|
||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) |
|
||||
| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) |
|
||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
|
||||
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
|
||||
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) |
|
||||
@@ -320,12 +326,15 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
| [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) |
|
||||
| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) |
|
||||
| manual | `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) |
|
||||
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
|
||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
|
||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
|
||||
| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) |
|
||||
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) |
|
||||
| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) |
|
||||
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/nifcloud) |
|
||||
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) |
|
||||
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/otc) |
|
||||
@@ -348,11 +357,12 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
|
||||
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) |
|
||||
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) |
|
||||
| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) |
|
||||
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) |
|
||||
| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) |
|
||||
|
||||
[^1]: more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
||||
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
|
||||
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production)
|
||||
[^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`.
|
||||
@@ -388,7 +398,7 @@ certificatesResolvers:
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||
```
|
||||
|
||||
#### Wildcard Domains
|
||||
@@ -427,7 +437,7 @@ The CA server to use:
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -455,7 +465,7 @@ certificatesResolvers:
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -472,7 +482,7 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||
```
|
||||
|
||||
!!! warning
|
||||
For concurrency reason, this file cannot be shared across multiple instances of Traefik.
|
||||
For concurrency reasons, this file cannot be shared across multiple instances of Traefik.
|
||||
|
||||
## Fallback
|
||||
|
||||
|
@@ -40,7 +40,7 @@ spec:
|
||||
domains:
|
||||
- main: example.org
|
||||
sans:
|
||||
- *.example.org
|
||||
- '*.example.org'
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
|
@@ -32,7 +32,7 @@ spec:
|
||||
- name: blog
|
||||
port: 8080
|
||||
tls:
|
||||
certresolver: myresolver
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
|
@@ -32,7 +32,7 @@ spec:
|
||||
- name: blog
|
||||
port: 8080
|
||||
tls:
|
||||
certresolver: myresolver
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
|
@@ -4,13 +4,13 @@
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.email=test@example.com
|
||||
--certificatesresolvers.myresolver.acme.email=test@example.com
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
|
||||
# CA server to use.
|
||||
# Uncomment the line to use Let's Encrypt's staging server,
|
||||
@@ -19,7 +19,7 @@
|
||||
# Optional
|
||||
# Default: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
|
||||
# KeyType to use.
|
||||
#
|
||||
@@ -28,38 +28,38 @@
|
||||
#
|
||||
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.keyType=RSA4096
|
||||
--certificatesresolvers.myresolver.acme.keytype=RSA4096
|
||||
|
||||
# Use a TLS-ALPN-01 ACME challenge.
|
||||
#
|
||||
# Optional (but recommended)
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.tlsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.tlschallenge=true
|
||||
|
||||
# Use a HTTP-01 ACME challenge.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
|
||||
# EntryPoint to use for the HTTP-01 challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
|
||||
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
|
||||
# Note: mandatory for wildcard certificate generation.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge=true
|
||||
|
||||
# DNS provider used.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.provider=digitalocean
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.provider=digitalocean
|
||||
|
||||
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
|
||||
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
|
||||
@@ -68,14 +68,14 @@
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
|
||||
|
||||
# Use following DNS servers to resolve the FQDN authority.
|
||||
#
|
||||
# Optional
|
||||
# Default: empty
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||
|
||||
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
|
||||
#
|
||||
@@ -85,4 +85,4 @@
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.disablePropagationCheck=true
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.disablepropagationcheck=true
|
||||
|
@@ -317,7 +317,7 @@ spec:
|
||||
### Strict SNI Checking
|
||||
|
||||
With strict SNI checking, Traefik won't allow connections from clients connections
|
||||
that do not specify a server_name extension.
|
||||
that do not specify a server_name extension or don't match any certificate configured on the tlsOption.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Dynamic configuration
|
||||
@@ -428,6 +428,7 @@ metadata:
|
||||
|
||||
spec:
|
||||
clientAuth:
|
||||
# the CA certificate is extracted from key `tls.ca` of the given secrets.
|
||||
secretNames:
|
||||
- secretCA
|
||||
clientAuthType: RequireAndVerifyClientCert
|
||||
|
@@ -12,9 +12,11 @@ The BasicAuth middleware is a quick way to restrict access to your services to k
|
||||
```yaml tab="Docker"
|
||||
# Declaring the user list
|
||||
#
|
||||
# Note: all dollar signs in the hash need to be doubled for escaping.
|
||||
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
|
||||
# To create user:password pair, it's possible to use this command:
|
||||
# echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
|
||||
#
|
||||
# Also note that dollar signs should NOT be doubled when they not evaluated (e.g. Ansible docker_container module).
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
@@ -64,6 +64,9 @@ http:
|
||||
* The `Accept-Encoding` request header contains `gzip`.
|
||||
* The response is not already compressed, i.e. the `Content-Encoding` response header is not already set.
|
||||
|
||||
If Content-Type header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
||||
It will also set accordingly the `Content-Type` header with the detected MIME type.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `excludedContentTypes`
|
||||
|
@@ -21,6 +21,9 @@ This middleware exists to enable the correct behavior until at least the default
|
||||
is still to automatically set the `Content-Type` header.
|
||||
Therefore, given the default value of the `autoDetect` option (false),
|
||||
simply enabling this middleware for a router switches the router's behavior.
|
||||
|
||||
The scope of the Content-Type middleware is the MIME type detection done by the core of Traefik (the server part).
|
||||
Therefore, it has no effect against any other `Content-Type` header modifications (e.g.: in another middleware such as compress).
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
|
@@ -151,8 +151,8 @@ metadata:
|
||||
name: testHeader
|
||||
spec:
|
||||
headers:
|
||||
frameDeny: "true"
|
||||
sslRedirect: "true"
|
||||
frameDeny: true
|
||||
sslRedirect: true
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
@@ -217,7 +217,7 @@ spec:
|
||||
- "https://foo.bar.org"
|
||||
- "https://example.org"
|
||||
accessControlMaxAge: 100
|
||||
addVaryHeader: "true"
|
||||
addVaryHeader: true
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
@@ -311,7 +311,7 @@ This value can contains a list of allowed origins.
|
||||
More information including how to use the settings can be found on:
|
||||
|
||||
- [Mozilla.org](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)
|
||||
- [w3](https://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
|
||||
- [w3](https://fetch.spec.whatwg.org/#http-access-control-allow-origin)
|
||||
- [IETF](https://tools.ietf.org/html/rfc6454#section-7.1)
|
||||
|
||||
Traefik no longer supports the null value, as it is [no longer recommended as a return value](https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null).
|
||||
@@ -322,7 +322,7 @@ The `accessControlExposeHeaders` indicates which headers are safe to expose to t
|
||||
|
||||
### `accessControlMaxAge`
|
||||
|
||||
The `accessControlMaxAge` indicates how long a preflight request can be cached.
|
||||
The `accessControlMaxAge` indicates how long (in seconds) a preflight request can be cached.
|
||||
|
||||
### `addVaryHeader`
|
||||
|
||||
|
@@ -208,7 +208,7 @@ metadata:
|
||||
spec:
|
||||
redirectScheme:
|
||||
# ...
|
||||
port: 443
|
||||
port: "443"
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
@@ -247,5 +247,7 @@ http:
|
||||
test-redirectscheme:
|
||||
redirectScheme:
|
||||
# ...
|
||||
port: 443
|
||||
port: "443"
|
||||
```
|
||||
|
||||
!!! info "Port in this configuration is a string, not a numeric value."
|
||||
|
@@ -50,7 +50,7 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
traefik.ingress.kubernetes.io/rule-type: PathPrefix
|
||||
spec:
|
||||
rules:
|
||||
- host: test.locahost
|
||||
- host: test.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /test
|
||||
@@ -97,7 +97,7 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.routers.router0.rule=Host(`example.com`) && PathPrefix(`/test`)"
|
||||
- "traefik.http.routers.router0.rule=Host(`test.localhost`) && PathPrefix(`/test`)"
|
||||
- "traefik.http.routers.router0.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
@@ -370,13 +370,13 @@ To apply a redirection:
|
||||
## static configuration
|
||||
|
||||
[entryPoints.web]
|
||||
address = 80
|
||||
address = ":80"
|
||||
[entryPoints.web.http.redirections.entryPoint]
|
||||
to = "websecure"
|
||||
scheme = "https"
|
||||
|
||||
[entryPoints.websecure]
|
||||
address = 443
|
||||
address = ":443"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
@@ -609,6 +609,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
|
||||
middlewares:
|
||||
- name: admin-stripprefix
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: admin-stripprefix
|
||||
@@ -799,6 +800,13 @@ There is no more log configuration at the root level.
|
||||
--log.format=json
|
||||
```
|
||||
|
||||
## Access Logs
|
||||
|
||||
Access Logs are configured in the same way as before.
|
||||
|
||||
But all request headers are now filtered out by default in Traefik v2.
|
||||
So during migration, you might want to consider enabling some needed fields (see [access log configuration](../observability/access-logs.md)).
|
||||
|
||||
## 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).
|
||||
|
@@ -1,5 +1,17 @@
|
||||
# Migration: Steps needed between the versions
|
||||
|
||||
## v2.2.2 to v2.2.5
|
||||
|
||||
### InsecureSNI removal
|
||||
|
||||
In `v2.2.2` we introduced a new flag (`insecureSNI`) which was available as a global option to disable domain fronting.
|
||||
Since `v2.2.5` this global option has been removed, and you should not use it anymore.
|
||||
|
||||
### HostSNI rule matcher removal
|
||||
|
||||
In `v2.2.2` we introduced a new rule matcher (`HostSNI`) which was allowing to match the Server Name Indication at the router level.
|
||||
Since `v2.2.5` this rule has been removed, and you should not use it anymore.
|
||||
|
||||
## v2.0 to v2.1
|
||||
|
||||
### Kubernetes CRD
|
||||
|
@@ -111,9 +111,9 @@ accessLog:
|
||||
--accesslog.filters.minduration=10ms
|
||||
```
|
||||
|
||||
### Limiting the Fields
|
||||
### Limiting the Fields/Including Headers
|
||||
|
||||
You can decide to limit the logged fields/headers to a given list with the `fields.names` and `fields.header` options
|
||||
You can decide to limit the logged fields/headers to a given list with the `fields.names` and `fields.headers` options.
|
||||
|
||||
Each field can be set to:
|
||||
|
||||
@@ -121,7 +121,7 @@ Each field can be set to:
|
||||
- `drop` to drop the value
|
||||
- `redact` to replace the value with "redacted"
|
||||
|
||||
The `defaultMode` for `fields.header` is `drop`.
|
||||
The `defaultMode` for `fields.headers` is `drop`.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Limiting the Logs to Specific Fields
|
||||
@@ -181,10 +181,10 @@ accessLog:
|
||||
| `StartUTC` | The time at which request processing started. |
|
||||
| `StartLocal` | The local time at which request processing started. |
|
||||
| `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. |
|
||||
| `BackendAddr` | The IP:port of the Traefik backend (extracted from `BackendURL`) |
|
||||
| `RouterName` | The name of the Traefik router. |
|
||||
| `ServiceName` | The name of the Traefik backend. |
|
||||
| `ServiceURL` | The URL of the Traefik backend. |
|
||||
| `ServiceAddr` | The IP:port of the Traefik backend (extracted from `ServiceURL`) |
|
||||
| `ClientAddr` | The remote address in its original form (usually IP:port). |
|
||||
| `ClientHost` | The remote IP address from which the client request was received. |
|
||||
| `ClientPort` | The remote TCP port from which the client request was received. |
|
||||
|
@@ -7,13 +7,14 @@ The tracing system allows developers to visualize call flows in their infrastruc
|
||||
|
||||
Traefik uses OpenTracing, an open standard designed for distributed tracing.
|
||||
|
||||
Traefik supports five tracing backends:
|
||||
Traefik supports six tracing backends:
|
||||
|
||||
- [Jaeger](./jaeger.md)
|
||||
- [Zipkin](./zipkin.md)
|
||||
- [Datadog](./datadog.md)
|
||||
- [Instana](./instana.md)
|
||||
- [Haystack](./haystack.md)
|
||||
- [Elastic](./elastic.md)
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@@ -72,9 +72,6 @@ to allow defining:
|
||||
- A [router rule](#dashboard-router-rule) for accessing the dashboard,
|
||||
through Traefik itself (sometimes referred as "Traefik-ception").
|
||||
|
||||
??? example "Dashboard Dynamic Configuration Examples"
|
||||
--8<-- "content/operations/include-api-examples.md"
|
||||
|
||||
### Dashboard Router Rule
|
||||
|
||||
As underlined in the [documentation for the `api.dashboard` option](./api.md#dashboard),
|
||||
@@ -99,6 +96,9 @@ rule = "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
|
||||
rule = "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
```
|
||||
|
||||
??? example "Dashboard Dynamic Configuration Examples"
|
||||
--8<-- "content/operations/include-dashboard-examples.md"
|
||||
|
||||
## Insecure Mode
|
||||
|
||||
This mode is not recommended because it does not allow the use of security features.
|
||||
|
101
docs/content/operations/include-dashboard-examples.md
Normal file
101
docs/content/operations/include-dashboard-examples.md
Normal file
@@ -0,0 +1,101 @@
|
||||
```yaml tab="Docker"
|
||||
# Dynamic Configuration
|
||||
labels:
|
||||
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
- "traefik.http.routers.dashboard.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="Docker (Swarm)"
|
||||
# Dynamic Configuration
|
||||
deploy:
|
||||
labels:
|
||||
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
- "traefik.http.routers.dashboard.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
# Dummy service for Swarm port detection. The port can be any valid integer value.
|
||||
- "traefik.http.services.dummy-svc.loadbalancer.server.port=9999"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes CRD"
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: traefik-dashboard
|
||||
spec:
|
||||
routes:
|
||||
- match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
middlewares:
|
||||
- name: auth
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: auth
|
||||
spec:
|
||||
basicAuth:
|
||||
secret: secretName # Kubernetes secret named "secretName"
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Dynamic Configuration
|
||||
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
- "traefik.http.routers.dashboard.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.routers.dashboard.rule": "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))",
|
||||
"traefik.http.routers.dashboard.service": "api@internal",
|
||||
"traefik.http.routers.dashboard.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.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
- "traefik.http.routers.dashboard.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.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
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:
|
||||
dashboard:
|
||||
rule: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
|
||||
service: api@internal
|
||||
middlewares:
|
||||
- auth
|
||||
middlewares:
|
||||
auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
@@ -154,7 +154,7 @@ You can specify which Docker API Endpoint to use with the directive [`endpoint`]
|
||||
|
||||
- Authentication with Client Certificates as described in ["Protect the Docker daemon socket."](https://docs.docker.com/engine/security/https/)
|
||||
- Authorize and filter requests to restrict possible actions with [the TecnativaDocker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy).
|
||||
- Authorization with the [Docker Authorization Plugin Mechanism](https://docs.docker.com/engine/extend/plugins_authorization/)
|
||||
- Authorization with the [Docker Authorization Plugin Mechanism](https://web.archive.org/web/20190920092526/https://docs.docker.com/engine/extend/plugins_authorization/)
|
||||
- Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik.
|
||||
- Accounting at container level, by exposing the socket on a another container than Traefik's.
|
||||
With Swarm mode, it allows scheduling of Traefik on worker nodes, with only the "socket exposer" container on the manager nodes.
|
||||
|
@@ -47,22 +47,22 @@ You can write one of these mutually exclusive configuration elements:
|
||||
middlewares = ["my-basic-auth"]
|
||||
service = "service-foo"
|
||||
rule = "Path(`/foo`)"
|
||||
|
||||
# Add the middleware
|
||||
[http.middlewares]
|
||||
[http.middlewares.my-basic-auth.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
usersFile = "etc/traefik/.htpasswd"
|
||||
|
||||
# Add the service
|
||||
[http.services]
|
||||
[http.services.service-foo]
|
||||
[http.services.service-foo.loadBalancer]
|
||||
[[http.services.service-foo.loadBalancer.servers]]
|
||||
url = "http://foo/"
|
||||
[[http.services.service-foo.loadBalancer.servers]]
|
||||
url = "http://bar/"
|
||||
|
||||
# Add the middleware
|
||||
[http.middlewares]
|
||||
[http.middlewares.my-basic-auth.basicAuth]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
usersFile = "etc/traefik/.htpasswd"
|
||||
|
||||
# Add the service
|
||||
[http.services]
|
||||
[http.services.service-foo]
|
||||
[http.services.service-foo.loadBalancer]
|
||||
[[http.services.service-foo.loadBalancer.servers]]
|
||||
url = "http://foo/"
|
||||
[[http.services.service-foo.loadBalancer.servers]]
|
||||
url = "http://bar/"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
@@ -191,14 +191,14 @@ providers:
|
||||
### Go Templating
|
||||
|
||||
!!! warning
|
||||
Go Templating only works along with dedicated dynamic configuration files.
|
||||
Go Templating only works with dedicated dynamic configuration files.
|
||||
Templating does not work in the Traefik main static configuration file.
|
||||
|
||||
Traefik allows using Go templating,
|
||||
it must be a valid [Go template](https://golang.org/pkg/text/template/),
|
||||
augmented with the [sprig template functions](http://masterminds.github.io/sprig/).
|
||||
Traefik supports using Go templating to automatically generate repetitive portions of configuration files.
|
||||
These sections must be valid [Go templates](https://golang.org/pkg/text/template/),
|
||||
augmented with the [Sprig template functions](http://masterminds.github.io/sprig/).
|
||||
|
||||
Thus, it's possible to define easily lot of routers, services and TLS certificates as described in the following examples:
|
||||
To illustrate, it's possible to easily define multiple routers, services, and TLS certificates as described in the following examples:
|
||||
|
||||
??? example "Configuring Using Templating"
|
||||
|
||||
|
@@ -173,7 +173,7 @@ Array of namespaces to watch.
|
||||
|
||||
### `labelselector`
|
||||
|
||||
_Optional,Default: empty (process all Ingresses)_
|
||||
_Optional,Default: empty (process all resources)_
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[providers.kubernetesCRD]
|
||||
@@ -192,8 +192,8 @@ providers:
|
||||
--providers.kubernetescrd.labelselector="A and not B"
|
||||
```
|
||||
|
||||
By default, Traefik processes all Ingress objects in the configured namespaces.
|
||||
A label selector can be defined to filter on specific Ingress objects only.
|
||||
By default, Traefik processes all resource objects in the configured namespaces.
|
||||
A label selector can be defined to filter on specific resource objects only.
|
||||
|
||||
See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details.
|
||||
|
||||
@@ -218,10 +218,10 @@ providers:
|
||||
--providers.kubernetescrd.ingressclass=traefik-internal
|
||||
```
|
||||
|
||||
Value of `kubernetes.io/ingress.class` annotation that identifies Ingress objects to be processed.
|
||||
Value of `kubernetes.io/ingress.class` annotation that identifies resource objects to be processed.
|
||||
|
||||
If the parameter is non-empty, only Ingresses containing an annotation with the same value are processed.
|
||||
Otherwise, Ingresses missing the annotation, having an empty value, or the value `traefik` are processed.
|
||||
If the parameter is non-empty, only resources containing an annotation with the same value are processed.
|
||||
Otherwise, resources missing the annotation, having an empty value, or the value `traefik` are processed.
|
||||
|
||||
### `throttleDuration`
|
||||
|
||||
|
@@ -358,17 +358,3 @@ providers:
|
||||
|
||||
If one wants to know more about the various aspects of the Ingress spec that Traefik supports,
|
||||
many examples of Ingresses definitions are located in the tests [data](https://github.com/containous/traefik/tree/v2.2/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
|
||||
|
||||
## LetsEncrypt Support with the Ingress Provider
|
||||
|
||||
By design, Traefik is a stateless application, meaning that it only derives its configuration from the environment it runs in, without additional configuration.
|
||||
For this reason, users can run multiple instances of Traefik at the same time to achieve HA, as is a common pattern in the kubernetes ecosystem.
|
||||
|
||||
When using a single instance of Traefik with LetsEncrypt, no issues should be encountered, however this could be a single point of failure.
|
||||
Unfortunately, it is not possible to run multiple instances of Traefik 2.0 with LetsEncrypt enabled, because there is no way to ensure that the correct instance of Traefik will receive the challenge request, and subsequent responses.
|
||||
Previous versions of Traefik used a [KV store](https://docs.traefik.io/v1.7/configuration/acme/#storage) to attempt to achieve this, but due to sub-optimal performance was dropped as a feature in 2.0.
|
||||
|
||||
If you require LetsEncrypt with HA in a kubernetes environment, we recommend using [TraefikEE](https://containo.us/traefikee/) where distributed LetsEncrypt is a supported feature.
|
||||
|
||||
If you are wanting to continue to run Traefik Community Edition, LetsEncrypt HA can be achieved by using a Certificate Controller such as [Cert-Manager](https://docs.cert-manager.io/en/latest/index.html).
|
||||
When using Cert-Manager to manage certificates, it will create secrets in your namespaces that can be referenced as TLS secrets in your [ingress objects](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls).
|
||||
|
@@ -147,7 +147,7 @@
|
||||
- "traefik.http.services.service01.loadbalancer.healthcheck.followredirects=true"
|
||||
- "traefik.http.services.service01.loadbalancer.passhostheader=true"
|
||||
- "traefik.http.services.service01.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||
- "traefik.http.services.service01.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie=true"
|
||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.httponly=true"
|
||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true"
|
||||
|
@@ -91,21 +91,11 @@ spec:
|
||||
services:
|
||||
- name: s1
|
||||
port: 80
|
||||
healthCheck:
|
||||
path: /health
|
||||
host: baz.com
|
||||
intervalSeconds: 7
|
||||
timeoutSeconds: 60
|
||||
# strategy defines the load balancing strategy between the servers. It defaults
|
||||
# to Round Robin, and for now only Round Robin is supported anyway.
|
||||
strategy: RoundRobin
|
||||
- name: s2
|
||||
port: 433
|
||||
healthCheck:
|
||||
path: /health
|
||||
host: baz.com
|
||||
intervalSeconds: 7
|
||||
timeoutSeconds: 60
|
||||
- match: PathPrefix(`/misc`)
|
||||
services:
|
||||
- name: s3
|
||||
@@ -133,7 +123,7 @@ spec:
|
||||
tls:
|
||||
secretName: supersecret
|
||||
options:
|
||||
name: myTLSOption
|
||||
name: my-tls-option
|
||||
namespace: default
|
||||
|
||||
---
|
||||
@@ -155,7 +145,7 @@ spec:
|
||||
secretName: foosecret
|
||||
passthrough: false
|
||||
options:
|
||||
name: myTLSOption
|
||||
name: my-tls-option
|
||||
namespace: default
|
||||
|
||||
---
|
||||
|
@@ -145,6 +145,7 @@
|
||||
"traefik.http.services.service01.loadbalancer.healthcheck.followredirects": "true",
|
||||
"traefik.http.services.service01.loadbalancer.passhostheader": "true",
|
||||
"traefik.http.services.service01.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.service01.loadbalancer.sticky.cookie": "true",
|
||||
"traefik.http.services.service01.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service01.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service01.loadbalancer.sticky.cookie.secure": "true",
|
||||
|
@@ -106,13 +106,13 @@ HTTP configuration.
|
||||
Default middlewares for the routers linked to the entry point.
|
||||
|
||||
`--entrypoints.<name>.http.redirections.entrypoint.permanent`:
|
||||
Applied a permanent redirection. Defaults to true. (Default: ```true```)
|
||||
Applies a permanent redirection. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.redirections.entrypoint.priority`:
|
||||
Priority of the generated router. Defaults to 1. (Default: ```1```)
|
||||
Priority of the generated router. (Default: ```2147483647```)
|
||||
|
||||
`--entrypoints.<name>.http.redirections.entrypoint.scheme`:
|
||||
Scheme used for the redirection. Defaults to https. (Default: ```https```)
|
||||
Scheme used for the redirection. (Default: ```https```)
|
||||
|
||||
`--entrypoints.<name>.http.redirections.entrypoint.to`:
|
||||
Targeted entry point of the redirection.
|
||||
|
@@ -106,13 +106,13 @@ HTTP configuration.
|
||||
Default middlewares for the routers linked to the entry point.
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_PERMANENT`:
|
||||
Applied a permanent redirection. Defaults to true. (Default: ```true```)
|
||||
Applies a permanent redirection. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_PRIORITY`:
|
||||
Priority of the generated router. Defaults to 1. (Default: ```1```)
|
||||
Priority of the generated router. (Default: ```2147483647```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME`:
|
||||
Scheme used for the redirection. Defaults to https. (Default: ```https```)
|
||||
Scheme used for the redirection. (Default: ```https```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_TO`:
|
||||
Targeted entry point of the redirection.
|
||||
|
@@ -152,7 +152,7 @@
|
||||
username = "foobar"
|
||||
password = "foobar"
|
||||
[providers.consul]
|
||||
rootKey = "traefik"
|
||||
rootKey = "foobar"
|
||||
endpoints = ["foobar", "foobar"]
|
||||
username = "foobar"
|
||||
password = "foobar"
|
||||
@@ -163,7 +163,7 @@
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[providers.etcd]
|
||||
rootKey = "traefik"
|
||||
rootKey = "foobar"
|
||||
endpoints = ["foobar", "foobar"]
|
||||
username = "foobar"
|
||||
password = "foobar"
|
||||
@@ -174,7 +174,7 @@
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[providers.zooKeeper]
|
||||
rootKey = "traefik"
|
||||
rootKey = "foobar"
|
||||
endpoints = ["foobar", "foobar"]
|
||||
username = "foobar"
|
||||
password = "foobar"
|
||||
@@ -185,7 +185,7 @@
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[providers.redis]
|
||||
rootKey = "traefik"
|
||||
rootKey = "foobar"
|
||||
endpoints = ["foobar", "foobar"]
|
||||
username = "foobar"
|
||||
password = "foobar"
|
||||
|
@@ -125,7 +125,7 @@ providers:
|
||||
- foobar
|
||||
labelSelector: foobar
|
||||
ingressClass: foobar
|
||||
throttleDuration: 10s
|
||||
throttleDuration: 42s
|
||||
rest:
|
||||
insecure: true
|
||||
rancher:
|
||||
@@ -162,7 +162,7 @@ providers:
|
||||
username: foobar
|
||||
password: foobar
|
||||
consul:
|
||||
rootKey: traefik
|
||||
rootKey: foobar
|
||||
endpoints:
|
||||
- foobar
|
||||
- foobar
|
||||
@@ -175,7 +175,7 @@ providers:
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
etcd:
|
||||
rootKey: traefik
|
||||
rootKey: foobar
|
||||
endpoints:
|
||||
- foobar
|
||||
- foobar
|
||||
@@ -188,10 +188,10 @@ providers:
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
zooKeeper:
|
||||
rootKey: traefik
|
||||
rootKey: foobar
|
||||
endpoints:
|
||||
- foobar
|
||||
- foobar
|
||||
- foobar
|
||||
- foobar
|
||||
username: foobar
|
||||
password: foobar
|
||||
tls:
|
||||
@@ -201,10 +201,10 @@ providers:
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
redis:
|
||||
rootKey: traefik
|
||||
rootKey: foobar
|
||||
endpoints:
|
||||
- foobar
|
||||
- foobar
|
||||
- foobar
|
||||
- foobar
|
||||
username: foobar
|
||||
password: foobar
|
||||
tls:
|
||||
|
@@ -91,7 +91,7 @@ and whether to listen for TCP or UDP.
|
||||
### General
|
||||
|
||||
EntryPoints are part of the [static configuration](../getting-started/configuration-overview.md#the-static-configuration).
|
||||
You can define them using a toml file, CLI arguments, or a key-value store.
|
||||
They can be defined by using a file (TOML or YAML) or CLI arguments.
|
||||
|
||||
??? info "See the complete reference for the list of available options"
|
||||
|
||||
@@ -168,7 +168,7 @@ The format is:
|
||||
|
||||
If both TCP and UDP are wanted for the same port, two entryPoints definitions are needed, such as in the example below.
|
||||
|
||||
??? example "Both TCP and UDP on port 3179"
|
||||
??? example "Both TCP and UDP on Port 3179"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
@@ -194,6 +194,30 @@ If both TCP and UDP are wanted for the same port, two entryPoints definitions ar
|
||||
--entryPoints.udpep.address=:3179/udp
|
||||
```
|
||||
|
||||
??? example "Listen on Specific IP Addresses Only"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints.specificIPv4]
|
||||
address = "192.168.2.7:8888"
|
||||
[entryPoints.specificIPv6]
|
||||
address = "[2001:db8::1]:8888"
|
||||
```
|
||||
|
||||
```yaml tab="File (yaml)"
|
||||
entryPoints:
|
||||
specificIPv4:
|
||||
address: "192.168.2.7:8888"
|
||||
specificIPv6:
|
||||
address: "[2001:db8::1]:8888"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
entrypoints.specificIPv4.address=192.168.2.7:8888
|
||||
entrypoints.specificIPv6.address=[2001:db8::1]:8888
|
||||
```
|
||||
|
||||
Full details for how to specify `address` can be found in [net.Listen](https://golang.org/pkg/net/#Listen) (and [net.Dial](https://golang.org/pkg/net/#Dial)) of the doc for go.
|
||||
|
||||
### Forwarded Headers
|
||||
|
||||
You can configure Traefik to trust the forwarded headers information (`X-Forwarded-*`).
|
||||
@@ -569,7 +593,7 @@ This whole section is dedicated to options, keyed by entry point, that will appl
|
||||
```bash tab="CLI"
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.web.http.redirections.entryPoint.to=websecure
|
||||
--entrypoints.web.http.redirections.entryPoint.https=true
|
||||
--entrypoints.web.http.redirections.entryPoint.scheme=https
|
||||
--entrypoints.websecure.address=:443
|
||||
```
|
||||
|
||||
|
@@ -291,7 +291,7 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||
See [health check](../services/index.md#health-check) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.interval=10"
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.interval=10s"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
|
||||
@@ -334,12 +334,12 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky`"
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
@@ -535,7 +535,7 @@ You can declare UDP Routers and/or Services using labels.
|
||||
my-container:
|
||||
# ...
|
||||
labels:
|
||||
- "traefik.udp.routers.my-router.entrypoint=udp"
|
||||
- "traefik.udp.routers.my-router.entrypoints=udp"
|
||||
- "traefik.udp.services.my-service.loadbalancer.server.port=4123"
|
||||
```
|
||||
|
||||
|
@@ -108,24 +108,24 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
|
||||
name: myingressroute
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
routes:
|
||||
- match: Host(`foo`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: ingressroute.tcp
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: ingressroute.tcp
|
||||
namespace: default
|
||||
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- tcpep
|
||||
@@ -135,22 +135,22 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8080
|
||||
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: ingressroute.udp
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- fooudp
|
||||
routes:
|
||||
- kind: Rule
|
||||
services:
|
||||
- name: whoamiudp
|
||||
port: 8080
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: ingressroute.udp
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- fooudp
|
||||
routes:
|
||||
- kind: Rule
|
||||
services:
|
||||
- name: whoamiudp
|
||||
port: 8080
|
||||
```
|
||||
|
||||
```yaml tab="Whoami"
|
||||
@@ -618,10 +618,12 @@ Register the `Middleware` [kind](../../reference/dynamic-configuration/kubernete
|
||||
|
||||
!!! important "Cross-provider namespace"
|
||||
|
||||
As Kubernetes also has its own notion of namespace, one should not confuse the kubernetes namespace of a resource
|
||||
(in the reference to the middleware) with the [provider namespace](../../middlewares/overview.md#provider-namespace),
|
||||
when the definition of the middleware comes from another provider.
|
||||
In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored.
|
||||
As Kubernetes also has its own notion of namespace, one should not confuse the kubernetes namespace of a resource
|
||||
(in the reference to the middleware) with the [provider namespace](../../middlewares/overview.md#provider-namespace),
|
||||
when the definition of the middleware comes from another provider.
|
||||
In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored.
|
||||
Additionally, when you want to reference a Middleware from the CRD Provider,
|
||||
you have to append the namespace of the resource in the resource-name as Traefik appends the namespace internally automatically.
|
||||
|
||||
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
|
||||
|
||||
|
@@ -202,7 +202,7 @@ which in turn will create the resulting routers, services, handlers, etc.
|
||||
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth@file,prefix@kuberntescrd,cb@file
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth@file,prefix@kubernetescrd,cb@file
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/router.priority`"
|
||||
@@ -282,12 +282,12 @@ which in turn will create the resulting routers, services, handlers, etc.
|
||||
traefik.ingress.kubernetes.io/service.passhostheader: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky`"
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie`"
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
```yaml
|
||||
traefik.ingress.kubernetes.io/service.sticky: "true"
|
||||
traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.name`"
|
||||
|
@@ -106,17 +106,9 @@ A Story of key & values
|
||||
|
||||
See [servers](../services/index.md#servers) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/scheme` | `http` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/servers/<n>/scheme`"
|
||||
|
||||
Overrides the default scheme.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|--------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/scheme` | `http` |
|
||||
| Key (Path) | Value |
|
||||
|-----------------------------------------------------------------|-----------------------------------------|
|
||||
| `traefik/http/services/myservice/loadbalancer/servers/0/url` | `http://<ip-server-1>:<port-server-1>/` |
|
||||
|
||||
??? info "`traefik/http/services/<service_name>/loadbalancer/passhostheader`"
|
||||
|
||||
@@ -381,9 +373,9 @@ You can declare TCP Routers and/or Services using KV.
|
||||
|
||||
See [servers](../services/index.md#servers) for more information.
|
||||
|
||||
| Key (Path) | Value |
|
||||
|-------------------------------------------------------------------|--------|
|
||||
| `traefik/tcp/services/mytcpservice/loadbalancer/servers/0/scheme` | `http` |
|
||||
| Key (Path) | Value |
|
||||
|--------------------------------------------------------------------|------------------|
|
||||
| `traefik/tcp/services/mytcpservice/loadbalancer/servers/0/address` | `xx.xx.xx.xx:xx` |
|
||||
|
||||
??? info "`traefik/tcp/services/<service_name>/loadbalancer/terminationdelay`"
|
||||
|
||||
|
@@ -232,12 +232,12 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
|
||||
"traefik.http.services.myservice.loadbalancer.healthcheck.followredirects": "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky`"
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
```json
|
||||
"traefik.http.services.myservice.loadbalancer.sticky": "true"
|
||||
"traefik.http.services.myservice.loadbalancer.sticky.cookie": "true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
@@ -238,12 +238,12 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
|
||||
- "traefik.http.services.myservice.loadbalancer.healthcheck.followredirects=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky`"
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
|
||||
|
||||
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
|
||||
|
||||
```yaml
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.myservice.loadbalancer.sticky.cookie=true"
|
||||
```
|
||||
|
||||
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
|
||||
|
@@ -232,11 +232,12 @@ The table below lists all the available matchers:
|
||||
|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
||||
| ```Headers(`key`, `value`)``` | Check if there is a key `key`defined in the headers, with the value `value` |
|
||||
| ```HeadersRegexp(`key`, `regexp`)``` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
|
||||
| ```Host(`example.com`, ...)``` | Check if the request domain targets one of the given `domains`. |
|
||||
| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
|
||||
| ```HostHeader(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
|
||||
| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Check if the request domain matches the given `regexp`. |
|
||||
| ```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. |
|
||||
| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)``` | Match exact request path. It accepts a sequence of literal and regular expression paths. |
|
||||
| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{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. |
|
||||
|
||||
!!! important "Regexp Syntax"
|
||||
@@ -471,6 +472,11 @@ It refers to a [TLS Options](../../https/tls.md#tls-options) and will be applied
|
||||
the TLS option is picked from the mapping mentioned above and based on the server name provided during the TLS handshake,
|
||||
and it all happens before routing actually occurs.
|
||||
|
||||
!!! info "Domain Fronting"
|
||||
|
||||
In the case of domain fronting,
|
||||
if the TLS options associated with the Host Header and the SNI are different then Traefik will respond with a status code `421`.
|
||||
|
||||
??? example "Configuring the TLS options"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
|
@@ -334,6 +334,12 @@ Below are the available options for the health check mechanism:
|
||||
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.
|
||||
|
||||
!!! warning "Health check in Kubernetes"
|
||||
|
||||
The Traefik health check is not available for `kubernetesCRD` and `kubernetesIngress` providers because Kubernetes
|
||||
already has a health check mechanism.
|
||||
Unhealthy pods will be removed by kubernetes. (cf [liveness documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-http-request))
|
||||
|
||||
??? example "Custom Interval & Timeout -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
```toml tab="TOML"
|
||||
|
@@ -131,7 +131,7 @@ The point is to manage those secret files by another mean, and read them from th
|
||||
!!! Note
|
||||
|
||||
You could store those secrets anywhere on the server,
|
||||
just make sure to use the proper path for the `file` directive fo the secrets definition in the `docker-compose.yml` file.
|
||||
just make sure to use the proper path for the `file` directive for the secrets definition in the `docker-compose.yml` file.
|
||||
|
||||
- Use this `docker-compose.yml` file:
|
||||
|
||||
|
@@ -26,11 +26,7 @@ theme:
|
||||
prev: 'Previous'
|
||||
next: 'Next'
|
||||
|
||||
copyright: "Copyright © 2016-2019 Containous"
|
||||
|
||||
google_analytics:
|
||||
- 'UA-51880359-3'
|
||||
- 'docs.traefik.io'
|
||||
copyright: "Copyright © 2016-2020 Containous"
|
||||
|
||||
extra_css:
|
||||
- assets/styles/extra.css # Our custom styles
|
||||
|
10
docs/theme/main.html
vendored
10
docs/theme/main.html
vendored
@@ -1,5 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block analytics %}
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','GTM-NMWC63S');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
|
||||
{% import "partials/language.html" as lang with context %}
|
||||
|
3
go.mod
3
go.mod
@@ -36,7 +36,7 @@ require (
|
||||
github.com/fatih/structs v1.1.0
|
||||
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.5.0
|
||||
github.com/go-acme/lego/v3 v3.8.0
|
||||
github.com/go-check/check v0.0.0-00010101000000-000000000000
|
||||
github.com/go-kit/kit v0.9.0
|
||||
github.com/gogo/protobuf v1.3.0 // indirect
|
||||
@@ -75,7 +75,6 @@ require (
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
||||
github.com/tinylib/msgp v1.0.2 // indirect
|
||||
github.com/transip/gotransip v5.8.2+incompatible // indirect
|
||||
github.com/uber/jaeger-client-go v2.22.1+incompatible
|
||||
github.com/uber/jaeger-lib v2.2.0+incompatible
|
||||
github.com/unrolled/render v1.0.2
|
||||
|
55
go.sum
55
go.sum
@@ -105,9 +105,8 @@ github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8 h1:6rJvj+NXjjauunLeS7uGy891F
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8/go.mod h1:aVvklgKsPENRkl29bNwrHISa1F+YLGTHArMxZMBqWM8=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee h1:NYqDBPkhVYt68W3yoGoRRi32i3MLx2ey7SFkJ1v/UI0=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.112 h1:E273ePcLllLIBGg5BHr3T0Fp1BJTvUyh5Y57ziSy81w=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.112/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
|
||||
github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -118,9 +117,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.16.23/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.23.0 h1:ilfJN/vJtFo1XDFxB2YMBYGeOvGZl6Qow17oyD4+Z9A=
|
||||
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/aws/aws-sdk-go v1.30.20 h1:ktsy2vodSZxz/arYqo7DlpkIeNohHL+4Rmjdo7YGtrE=
|
||||
github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
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=
|
||||
@@ -128,6 +126,8 @@ 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
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/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
|
||||
@@ -183,8 +183,8 @@ github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pq
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
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/cpu/goacmedns v0.0.2 h1:hYAgjnPu7HogTgb8trqQouR/RrBgXq1TPBgmxbK9eRA=
|
||||
github.com/cpu/goacmedns v0.0.2/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -196,8 +196,8 @@ github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TR
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2 h1:G9/PqfhOrt8JXnw0DGTfVoOkKHDhOlEZqhE/cu+NvQM=
|
||||
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/dnsimple/dnsimple-go v0.30.0 h1:IBIrn9jMKRMwporIRwdFyKdnHXVmwy6obnguB+ZMDIY=
|
||||
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/dnsimple/dnsimple-go v0.60.0 h1:N+q+ML1CZGf+5r4udu9Opy7WJNtOaFT9aM86Af9gLhk=
|
||||
github.com/dnsimple/dnsimple-go v0.60.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0 h1:hlGHcYGaaHs/yffSubcUKlp8TyV1v7qhcZZ5nGNQ2Fw=
|
||||
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
@@ -261,8 +261,8 @@ github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2/go.mod h1:GLy
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-acme/lego/v3 v3.5.0 h1:/0+NJQK+hNwRznhCi+19lbEa4xufhe7wJZOVd5j486s=
|
||||
github.com/go-acme/lego/v3 v3.5.0/go.mod h1:TXodhTGOiWEqXDdgrzBoCtJ5R4L9lfOE68CTM0KGkT0=
|
||||
github.com/go-acme/lego/v3 v3.8.0 h1:9OOEn54eZvEPRRdM7xiC5f7EBW0MlEeChr+kzlIhdN8=
|
||||
github.com/go-acme/lego/v3 v3.8.0/go.mod h1:kYiHYgSRzb1l2NQPWvWvkVG5etNCusGFsZc2MTak3m0=
|
||||
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=
|
||||
@@ -291,6 +291,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
@@ -405,6 +406,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6K
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
@@ -414,6 +417,8 @@ github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
|
||||
@@ -453,6 +458,8 @@ github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
@@ -473,8 +480,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181 h1:TrxPzApUukas24OMMVDUMlCs1XCExJtnGaDEiIAR4oQ=
|
||||
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -540,6 +547,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
|
||||
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
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=
|
||||
@@ -562,8 +571,8 @@ github.com/nrdcg/auroradns v1.0.1 h1:m/kBq83Xvy3cU261MOknd8BdnOk12q4lAWM+kOdsC2Y
|
||||
github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI=
|
||||
github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U=
|
||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/goinwx v0.6.1 h1:AJnjoWPELyCtofhGcmzzcEMFd9YdF2JB/LgutWsWt/s=
|
||||
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||
github.com/nrdcg/goinwx v0.7.0 h1:j6JlOp0nNwtvaP09TvKqc9pktjH81nOad0+Gx9S1t9U=
|
||||
github.com/nrdcg/goinwx v0.7.0/go.mod h1:4tKJOCi/1lTxuw9/yB2Ez0aojwtUCSkckjc22eALpqE=
|
||||
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
@@ -622,11 +631,15 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
|
||||
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
@@ -670,7 +683,6 @@ github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9L
|
||||
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=
|
||||
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
@@ -714,9 +726,8 @@ github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
||||
github.com/transip/gotransip v5.8.2+incompatible h1:aNJhw/w/3QBqFcHAIPz1ytoK5FexeMzbUCGrrhWr3H0=
|
||||
github.com/transip/gotransip v5.8.2+incompatible/go.mod h1:uacMoJVmrfOcscM4Bi5NVg708b7c6rz2oDTWqa7i2Ic=
|
||||
github.com/transip/gotransip/v6 v6.0.2 h1:rOCMY607PYF+YvMHHtJt7eZRd0mx/uhyz6dsXWPmn+4=
|
||||
github.com/transip/gotransip/v6 v6.0.2/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo=
|
||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||
@@ -736,8 +747,8 @@ github.com/vulcand/oxy v1.1.0 h1:DbBijGo1+6cFqR9jarkMxasdj0lgWwrrFtue6ijek4Q=
|
||||
github.com/vulcand/oxy v1.1.0/go.mod h1:ADiMYHi8gkGl2987yQIzDRoXZilANF4WtKaQ92OppKY=
|
||||
github.com/vulcand/predicate v1.1.0 h1:Gq/uWopa4rx/tnZu2opOSBqHK63Yqlou/SzrbwdJiNg=
|
||||
github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg=
|
||||
github.com/vultr/govultr v0.1.4 h1:UnNMixYFVO0p80itc8PcweoVENyo1PasfvwKhoasR9U=
|
||||
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
|
||||
github.com/vultr/govultr v0.4.2 h1:9i8xKZ+xp6vwZ9raqHoBLzhB4wCnMj7nOQTj5YIRLWY=
|
||||
github.com/vultr/govultr v0.4.2/go.mod h1:TUuUizMOFc7z+PNMssb6iGjKjQfpw5arIaOLfocVudQ=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
|
@@ -24,7 +24,7 @@ const (
|
||||
traefikTestAccessLogFile = "access.log"
|
||||
)
|
||||
|
||||
// AccessLogSuite
|
||||
// AccessLogSuite tests suite.
|
||||
type AccessLogSuite struct{ BaseSuite }
|
||||
|
||||
type accessLogValue struct {
|
||||
@@ -111,6 +111,20 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
||||
routerName: "rt-authFrontend",
|
||||
serviceURL: "-",
|
||||
},
|
||||
{
|
||||
formatOnly: false,
|
||||
code: "401",
|
||||
user: "test",
|
||||
routerName: "rt-authFrontend",
|
||||
serviceURL: "-",
|
||||
},
|
||||
{
|
||||
formatOnly: false,
|
||||
code: "200",
|
||||
user: "test",
|
||||
routerName: "rt-authFrontend",
|
||||
serviceURL: "http://172.17.0",
|
||||
},
|
||||
}
|
||||
|
||||
// Start Traefik
|
||||
@@ -130,7 +144,7 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
||||
// Verify Traefik started OK
|
||||
checkTraefikStarted(c)
|
||||
|
||||
// Test auth frontend
|
||||
// Test auth entrypoint
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8006/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = "frontend.auth.docker.local"
|
||||
@@ -138,6 +152,16 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req.SetBasicAuth("test", "")
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req.SetBasicAuth("test", "test")
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Verify access.log output as expected
|
||||
count := checkAccessLogExactValuesOutput(c, expected)
|
||||
|
||||
@@ -158,6 +182,13 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
|
||||
routerName: "rt-digestAuthMiddleware",
|
||||
serviceURL: "-",
|
||||
},
|
||||
{
|
||||
formatOnly: false,
|
||||
code: "401",
|
||||
user: "test",
|
||||
routerName: "rt-digestAuthMiddleware",
|
||||
serviceURL: "-",
|
||||
},
|
||||
{
|
||||
formatOnly: false,
|
||||
code: "200",
|
||||
@@ -192,15 +223,22 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
|
||||
resp, err := try.ResponseUntilStatusCode(req, 500*time.Millisecond, http.StatusUnauthorized)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
digestParts := digestParts(resp)
|
||||
digestParts["uri"] = "/"
|
||||
digestParts["method"] = http.MethodGet
|
||||
digestParts["username"] = "test"
|
||||
digestParts["password"] = "test"
|
||||
digest := digestParts(resp)
|
||||
digest["uri"] = "/"
|
||||
digest["method"] = http.MethodGet
|
||||
digest["username"] = "test"
|
||||
digest["password"] = "wrong"
|
||||
|
||||
req.Header.Set("Authorization", getDigestAuthorization(digestParts))
|
||||
req.Header.Set("Authorization", getDigestAuthorization(digest))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
digest["password"] = "test"
|
||||
|
||||
req.Header.Set("Authorization", getDigestAuthorization(digest))
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
@@ -562,7 +600,7 @@ func extractLines(c *check.C) []string {
|
||||
func checkStatsForLogFile(c *check.C) {
|
||||
err := try.Do(1*time.Second, func() error {
|
||||
if _, errStat := os.Stat(traefikTestLogFile); errStat != nil {
|
||||
return fmt.Errorf("could not get stats for log file: %s", errStat)
|
||||
return fmt.Errorf("could not get stats for log file: %w", errStat)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ACME test suites (using libcompose)
|
||||
// ACME test suites (using libcompose).
|
||||
type AcmeSuite struct {
|
||||
BaseSuite
|
||||
pebbleIP string
|
||||
@@ -74,7 +74,7 @@ func setupPebbleRootCA() (*http.Transport, error) {
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
|
||||
return nil, fmt.Errorf("error creating x509 cert pool from %q: %v", path, err)
|
||||
return nil, fmt.Errorf("error creating x509 cert pool from %q: %w", path, err)
|
||||
}
|
||||
|
||||
return &http.Transport{
|
||||
@@ -394,7 +394,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSAN(c *check.C) {
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test Let's encrypt down
|
||||
// Test Let's encrypt down.
|
||||
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
|
||||
Acme: map[string]static.CertificateResolver{
|
||||
@@ -417,7 +417,7 @@ func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// Doing an HTTPS request and test the response certificate
|
||||
// Doing an HTTPS request and test the response certificate.
|
||||
func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
|
||||
if len(testCase.template.PortHTTP) == 0 {
|
||||
testCase.template.PortHTTP = ":5002"
|
||||
@@ -444,7 +444,7 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
|
||||
// A real file is needed to have the right mode on acme.json file
|
||||
defer os.Remove("/tmp/acme.json")
|
||||
|
||||
backend := startTestServer("9010", http.StatusOK)
|
||||
backend := startTestServer("9010", http.StatusOK, "")
|
||||
defer backend.Close()
|
||||
|
||||
for _, sub := range testCase.subCases {
|
||||
|
@@ -47,7 +47,7 @@ func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||
leader, err := s.consulClient.Status().Leader()
|
||||
|
||||
if err != nil || len(leader) == 0 {
|
||||
return fmt.Errorf("leader not found. %v", err)
|
||||
return fmt.Errorf("leader not found. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Consul test suites (using libcompose)
|
||||
// Consul test suites (using libcompose).
|
||||
type ConsulSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
@@ -138,7 +138,7 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
|
||||
expectedJSON := filepath.FromSlash("testdata/rawdata-consul.json")
|
||||
|
||||
if *updateExpected {
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0666)
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0o666)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,7 @@ const (
|
||||
composeProject = "minimal"
|
||||
)
|
||||
|
||||
// Docker test suites
|
||||
// Docker tests suite.
|
||||
type DockerComposeSuite struct {
|
||||
BaseSuite
|
||||
}
|
||||
@@ -36,8 +36,8 @@ func (s *DockerComposeSuite) TearDownSuite(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
|
||||
var serviceCount = 2
|
||||
var composeService = "whoami1"
|
||||
serviceCount := 2
|
||||
composeService := "whoami1"
|
||||
|
||||
s.composeProject.Scale(c, composeService, serviceCount)
|
||||
|
||||
|
@@ -17,14 +17,14 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Images to have or pull before the build in order to make it work
|
||||
// FIXME handle this offline but loading them before build
|
||||
// Images to have or pull before the build in order to make it work.
|
||||
// FIXME handle this offline but loading them before build.
|
||||
var RequiredImages = map[string]string{
|
||||
"swarm": "1.0.0",
|
||||
"containous/whoami": "latest",
|
||||
}
|
||||
|
||||
// Docker test suites
|
||||
// Docker tests suite.
|
||||
type DockerSuite struct {
|
||||
BaseSuite
|
||||
project *docker.Project
|
||||
@@ -43,7 +43,7 @@ func (s *DockerSuite) startContainerWithLabels(c *check.C, image string, labels
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) startContainerWithNameAndLabels(c *check.C, name string, image string, labels map[string]string, args ...string) string {
|
||||
func (s *DockerSuite) startContainerWithNameAndLabels(c *check.C, name, image string, labels map[string]string, args ...string) string {
|
||||
return s.startContainerWithConfig(c, image, d.ContainerConfig{
|
||||
Name: name,
|
||||
Cmd: args,
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ErrorPagesSuite test suites (using libcompose)
|
||||
// ErrorPagesSuite test suites (using libcompose).
|
||||
type ErrorPagesSuite struct {
|
||||
BaseSuite
|
||||
ErrorPageIP string
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// etcd test suites (using libcompose)
|
||||
// etcd test suites (using libcompose).
|
||||
type EtcdSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
@@ -138,7 +138,7 @@ func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
|
||||
expectedJSON := filepath.FromSlash("testdata/rawdata-etcd.json")
|
||||
|
||||
if *updateExpected {
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0666)
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0o666)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// File test suites
|
||||
// File tests suite.
|
||||
type FileSuite struct{ BaseSuite }
|
||||
|
||||
func (s *FileSuite) SetUpSuite(c *check.C) {
|
||||
@@ -32,7 +32,7 @@ func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// #56 regression test, make sure it does not fail
|
||||
// #56 regression test, make sure it does not fail?
|
||||
func (s *FileSuite) TestSimpleConfigurationNoPanic(c *check.C) {
|
||||
cmd, display := s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml"))
|
||||
defer display(c)
|
||||
|
@@ -2,6 +2,9 @@
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
|
||||
@@ -24,6 +27,11 @@
|
||||
rule = "Host(`test2.localhost`)"
|
||||
service = "service1"
|
||||
|
||||
[http.routers.router3]
|
||||
rule = "Host(`internal.localhost`)"
|
||||
middlewares = ["secure"]
|
||||
service = "api@internal"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.secure.headers]
|
||||
featurePolicy = "vibrate 'none';"
|
||||
|
53
integration/fixtures/https/https_domain_fronting.toml
Normal file
53
integration/fixtures/https/https_domain_fronting.toml
Normal file
@@ -0,0 +1,53 @@
|
||||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
|
||||
[entryPoints.websecure]
|
||||
address = ":4443"
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.routers.router1]
|
||||
rule = "Host(`site1.www.snitest.com`)"
|
||||
service = "service1"
|
||||
[http.routers.router1.tls]
|
||||
|
||||
[http.routers.router2]
|
||||
rule = "Host(`site2.www.snitest.com`)"
|
||||
service = "service2"
|
||||
[http.routers.router2.tls]
|
||||
|
||||
[http.routers.router3]
|
||||
rule = "Host(`site3.www.snitest.com`)"
|
||||
service = "service3"
|
||||
[http.routers.router3.tls]
|
||||
options = "mytls"
|
||||
|
||||
[http.services.service1]
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:9010"
|
||||
|
||||
[http.services.service2]
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:9020"
|
||||
|
||||
[http.services.service3]
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:9030"
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "fixtures/https/wildcard.www.snitest.com.cert"
|
||||
keyFile = "fixtures/https/wildcard.www.snitest.com.key"
|
||||
|
||||
[tls.options]
|
||||
[tls.options.mytls]
|
||||
maxVersion = "VersionTLS12"
|
@@ -19,12 +19,14 @@ import (
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var LocalhostCert []byte
|
||||
var LocalhostKey []byte
|
||||
var (
|
||||
LocalhostCert []byte
|
||||
LocalhostKey []byte
|
||||
)
|
||||
|
||||
const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
|
||||
// GRPCSuite
|
||||
// GRPCSuite tests suite.
|
||||
type GRPCSuite struct{ BaseSuite }
|
||||
|
||||
type myserver struct {
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Headers test suites
|
||||
// Headers tests suite.
|
||||
type HeadersSuite struct{ BaseSuite }
|
||||
|
||||
func (s *HeadersSuite) TestSimpleConfiguration(c *check.C) {
|
||||
@@ -35,7 +35,7 @@ func (s *HeadersSuite) TestCorsResponses(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
backend := startTestServer("9000", http.StatusOK)
|
||||
backend := startTestServer("9000", http.StatusOK, "")
|
||||
defer backend.Close()
|
||||
|
||||
err = try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||
@@ -124,23 +124,25 @@ func (s *HeadersSuite) TestSecureHeadersResponses(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
backend := startTestServer("9000", http.StatusOK)
|
||||
backend := startTestServer("9000", http.StatusOK, "")
|
||||
defer backend.Close()
|
||||
|
||||
err = try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
testCase := []struct {
|
||||
desc string
|
||||
expected http.Header
|
||||
reqHost string
|
||||
desc string
|
||||
expected http.Header
|
||||
reqHost string
|
||||
internalReqHost string
|
||||
}{
|
||||
{
|
||||
desc: "Feature-Policy Set",
|
||||
expected: http.Header{
|
||||
"Feature-Policy": {"vibrate 'none';"},
|
||||
},
|
||||
reqHost: "test.localhost",
|
||||
reqHost: "test.localhost",
|
||||
internalReqHost: "internal.localhost",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -149,7 +151,14 @@ func (s *HeadersSuite) TestSecureHeadersResponses(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = test.reqHost
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.HasHeaderStruct(test.expected))
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasHeaderStruct(test.expected))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/api/rawdata", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = test.internalReqHost
|
||||
|
||||
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasHeaderStruct(test.expected))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HealthCheck test suites (using libcompose)
|
||||
// HealthCheck test suites (using libcompose).
|
||||
type HealthCheckSuite struct {
|
||||
BaseSuite
|
||||
whoami1IP string
|
||||
@@ -206,7 +206,7 @@ func (s *HealthCheckSuite) TestPortOverload(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// Checks if all the loadbalancers created will correctly update the server status
|
||||
// Checks if all the loadbalancers created will correctly update the server status.
|
||||
func (s *HealthCheckSuite) TestMultipleRoutersOnSameService(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/healthcheck/multiple-routers-one-same-service.toml", struct {
|
||||
Server1 string
|
||||
|
@@ -15,9 +15,12 @@ It has these top-level messages:
|
||||
*/
|
||||
package helloworld
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import (
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
@@ -26,9 +29,11 @@ import (
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
var (
|
||||
_ = proto.Marshal
|
||||
_ = fmt.Errorf
|
||||
_ = math.Inf
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
@@ -102,8 +107,10 @@ func init() {
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
var (
|
||||
_ context.Context
|
||||
_ grpc.ClientConn
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
|
@@ -18,7 +18,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HTTPSSuite
|
||||
// HTTPSSuite tests suite.
|
||||
type HTTPSSuite struct{ BaseSuite }
|
||||
|
||||
// TestWithSNIConfigHandshake involves a client sending a SNI hostname of
|
||||
@@ -73,8 +73,8 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`snitest.org`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend1 := startTestServer("9010", http.StatusNoContent, "")
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
defer backend1.Close()
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -129,8 +129,8 @@ func (s *HTTPSSuite) TestWithTLSOptions(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`snitest.org`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend1 := startTestServer("9010", http.StatusNoContent, "")
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
defer backend1.Close()
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -215,8 +215,8 @@ func (s *HTTPSSuite) TestWithConflictingTLSOptions(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`snitest.net`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend1 := startTestServer("9010", http.StatusNoContent, "")
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
defer backend1.Close()
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -441,7 +441,7 @@ func (s *HTTPSSuite) TestWithOverlappingDynamicCertificate(c *check.C) {
|
||||
}
|
||||
|
||||
// TestWithClientCertificateAuthentication
|
||||
// The client can send a certificate signed by a CA trusted by the server but it's optional
|
||||
// The client can send a certificate signed by a CA trusted by the server but it's optional.
|
||||
func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/https/clientca/https_1ca1config.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
@@ -499,7 +499,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
|
||||
}
|
||||
|
||||
// TestWithClientCertificateAuthentication
|
||||
// Use two CA:s and test that clients with client signed by either of them can connect
|
||||
// Use two CA:s and test that clients with client signed by either of them can connect.
|
||||
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check.C) {
|
||||
server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) }))
|
||||
server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) }))
|
||||
@@ -596,7 +596,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check
|
||||
}
|
||||
|
||||
// TestWithClientCertificateAuthentication
|
||||
// Use two CA:s in two different files and test that clients with client signed by either of them can connect
|
||||
// Use two CA:s in two different files and test that clients with client signed by either of them can connect.
|
||||
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAsMultipleFiles(c *check.C) {
|
||||
server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) }))
|
||||
server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) }))
|
||||
@@ -733,9 +733,12 @@ func (s *HTTPSSuite) TestWithRootCAsFileForHTTPSOnBackend(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func startTestServer(port string, statusCode int) (ts *httptest.Server) {
|
||||
func startTestServer(port string, statusCode int, textContent string) (ts *httptest.Server) {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(statusCode)
|
||||
if textContent != "" {
|
||||
_, _ = w.Write([]byte(textContent))
|
||||
}
|
||||
})
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:"+port)
|
||||
if err != nil {
|
||||
@@ -787,8 +790,8 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithNoChange(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`"+tr1.TLSClientConfig.ServerName+"`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend1 := startTestServer("9010", http.StatusNoContent, "")
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
defer backend1.Close()
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -856,8 +859,8 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithChange(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`"+tr2.TLSClientConfig.ServerName+"`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend1 := startTestServer("9010", http.StatusNoContent, "")
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
defer backend1.Close()
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -919,7 +922,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithTlsConfigurationDeletion(c
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`"+tr2.TLSClientConfig.ServerName+"`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
backend2 := startTestServer("9020", http.StatusResetContent, "")
|
||||
|
||||
defer backend2.Close()
|
||||
|
||||
@@ -956,11 +959,13 @@ func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName str
|
||||
if len(certFileName) > 0 {
|
||||
tlsConf := dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*traefiktls.CertAndStores{{
|
||||
Certificate: traefiktls.Certificate{
|
||||
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
}},
|
||||
Certificates: []*traefiktls.CertAndStores{
|
||||
{
|
||||
Certificate: traefiktls.Certificate{
|
||||
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1109,3 +1114,115 @@ func (s *HTTPSSuite) TestWithSNIDynamicCaseInsensitive(c *check.C) {
|
||||
proto := conn.ConnectionState().NegotiatedProtocol
|
||||
c.Assert(proto, checker.Equals, "h2")
|
||||
}
|
||||
|
||||
// TestWithDomainFronting verify the domain fronting behavior
|
||||
func (s *HTTPSSuite) TestWithDomainFronting(c *check.C) {
|
||||
backend := startTestServer("9010", http.StatusOK, "server1")
|
||||
defer backend.Close()
|
||||
backend2 := startTestServer("9020", http.StatusOK, "server2")
|
||||
defer backend2.Close()
|
||||
backend3 := startTestServer("9030", http.StatusOK, "server3")
|
||||
defer backend3.Close()
|
||||
|
||||
file := s.adaptFile(c, "fixtures/https/https_domain_fronting.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// wait for Traefik
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.BodyContains("Host(`site1.www.snitest.com`)"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
hostHeader string
|
||||
serverName string
|
||||
expectedContent string
|
||||
expectedStatusCode int
|
||||
}{
|
||||
{
|
||||
desc: "SimpleCase",
|
||||
hostHeader: "site1.www.snitest.com",
|
||||
serverName: "site1.www.snitest.com",
|
||||
expectedContent: "server1",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Simple case with port in the Host Header",
|
||||
hostHeader: "site3.www.snitest.com:4443",
|
||||
serverName: "site3.www.snitest.com",
|
||||
expectedContent: "server3",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Spaces after the host header",
|
||||
hostHeader: "site3.www.snitest.com ",
|
||||
serverName: "site3.www.snitest.com",
|
||||
expectedContent: "server3",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Spaces after the servername",
|
||||
hostHeader: "site3.www.snitest.com",
|
||||
serverName: "site3.www.snitest.com ",
|
||||
expectedContent: "server3",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Spaces after the servername and host header",
|
||||
hostHeader: "site3.www.snitest.com ",
|
||||
serverName: "site3.www.snitest.com ",
|
||||
expectedContent: "server3",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Domain Fronting with same tlsOptions should follow header",
|
||||
hostHeader: "site1.www.snitest.com",
|
||||
serverName: "site2.www.snitest.com",
|
||||
expectedContent: "server1",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Domain Fronting with same tlsOptions should follow header (2)",
|
||||
hostHeader: "site2.www.snitest.com",
|
||||
serverName: "site1.www.snitest.com",
|
||||
expectedContent: "server2",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Domain Fronting with different tlsOptions should produce a 421",
|
||||
hostHeader: "site2.www.snitest.com",
|
||||
serverName: "site3.www.snitest.com",
|
||||
expectedContent: "",
|
||||
expectedStatusCode: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
desc: "Domain Fronting with different tlsOptions should produce a 421 (2)",
|
||||
hostHeader: "site3.www.snitest.com",
|
||||
serverName: "site1.www.snitest.com",
|
||||
expectedContent: "",
|
||||
expectedStatusCode: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
desc: "Case insensitive",
|
||||
hostHeader: "sIte1.www.snitest.com",
|
||||
serverName: "sitE1.www.snitest.com",
|
||||
expectedContent: "server1",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = test.hostHeader
|
||||
|
||||
err = try.RequestWithTransport(req, 500*time.Millisecond, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true, ServerName: test.serverName}}, try.StatusCodeIs(test.expectedStatusCode), try.BodyContains(test.expectedContent))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
@@ -21,10 +21,12 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
var integration = flag.Bool("integration", false, "run integration tests")
|
||||
var container = flag.Bool("container", false, "run container integration tests")
|
||||
var host = flag.Bool("host", false, "run host integration tests")
|
||||
var showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
||||
var (
|
||||
integration = flag.Bool("integration", false, "run integration tests")
|
||||
container = flag.Bool("container", false, "run container integration tests")
|
||||
host = flag.Bool("host", false, "run host integration tests")
|
||||
showLog = flag.Bool("tlog", false, "always show Traefik logs")
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
if !*integration {
|
||||
|
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata")
|
||||
|
||||
// K8sSuite
|
||||
// K8sSuite tests suite.
|
||||
type K8sSuite struct{ BaseSuite }
|
||||
|
||||
func (s *K8sSuite) SetUpSuite(c *check.C) {
|
||||
@@ -119,7 +119,7 @@ func testConfiguration(c *check.C, path, apiPort string) {
|
||||
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = ioutil.WriteFile(expectedJSON, newJSON, 0644)
|
||||
err = ioutil.WriteFile(expectedJSON, newJSON, 0o644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Errorf("We do not want a passing test in file update mode")
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func matchesConfig(wantConfig string, buf *bytes.Buffer) try.ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if err := res.Body.Close(); err != nil {
|
||||
|
@@ -16,7 +16,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Log rotation integration test suite
|
||||
// Log rotation integration test suite.
|
||||
type LogRotationSuite struct{ BaseSuite }
|
||||
|
||||
func (s *LogRotationSuite) SetUpSuite(c *check.C) {
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose)
|
||||
// Marathon test suites (using libcompose).
|
||||
type MarathonSuite15 struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
@@ -55,7 +55,7 @@ func (s *MarathonSuite15) extendDockerHostsFile(host, ipAddr string) error {
|
||||
// (See also https://groups.google.com/d/topic/docker-user/JOGE7AnJ3Gw/discussion.)
|
||||
if os.Getenv("CONTAINER") == "DOCKER" {
|
||||
// We are running inside a container -- extend the hosts file.
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0600)
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ const (
|
||||
containerNameMarathon = "marathon"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose)
|
||||
// Marathon test suites (using libcompose).
|
||||
type MarathonSuite struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
@@ -60,7 +60,7 @@ func (s *MarathonSuite) extendDockerHostsFile(host, ipAddr string) error {
|
||||
// (See also https://groups.google.com/d/topic/docker-user/JOGE7AnJ3Gw/discussion.)
|
||||
if os.Getenv("CONTAINER") == "DOCKER" {
|
||||
// We are running inside a container -- extend the hosts file.
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0600)
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Redis test suites (using libcompose)
|
||||
// Redis test suites (using libcompose).
|
||||
type RedisSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
@@ -138,7 +138,7 @@ func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
|
||||
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
|
||||
|
||||
if *updateExpected {
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0666)
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0o666)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// SimpleSuite
|
||||
// SimpleSuite tests suite.
|
||||
type SimpleSuite struct{ BaseSuite }
|
||||
|
||||
func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) {
|
||||
|
2
integration/testdata/rawdata-consul.json
vendored
2
integration/testdata/rawdata-consul.json
vendored
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"dashboard_redirect@internal": {
|
||||
"redirectRegex": {
|
||||
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
|
||||
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
|
||||
"replacement": "${1}/dashboard/",
|
||||
"permanent": true
|
||||
},
|
||||
|
2
integration/testdata/rawdata-etcd.json
vendored
2
integration/testdata/rawdata-etcd.json
vendored
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"dashboard_redirect@internal": {
|
||||
"redirectRegex": {
|
||||
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
|
||||
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
|
||||
"replacement": "${1}/dashboard/",
|
||||
"permanent": true
|
||||
},
|
||||
|
2
integration/testdata/rawdata-ingress.json
vendored
2
integration/testdata/rawdata-ingress.json
vendored
@@ -54,7 +54,7 @@
|
||||
"middlewares": {
|
||||
"dashboard_redirect@internal": {
|
||||
"redirectRegex": {
|
||||
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
|
||||
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
|
||||
"replacement": "${1}/dashboard/",
|
||||
"permanent": true
|
||||
},
|
||||
|
2
integration/testdata/rawdata-redis.json
vendored
2
integration/testdata/rawdata-redis.json
vendored
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"dashboard_redirect@internal": {
|
||||
"redirectRegex": {
|
||||
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
|
||||
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
|
||||
"replacement": "${1}/dashboard/",
|
||||
"permanent": true
|
||||
},
|
||||
|
2
integration/testdata/rawdata-zk.json
vendored
2
integration/testdata/rawdata-zk.json
vendored
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"dashboard_redirect@internal": {
|
||||
"redirectRegex": {
|
||||
"regex": "^(http:\\/\\/[^:\\/]+(:\\d+)?)\\/$",
|
||||
"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
|
||||
"replacement": "${1}/dashboard/",
|
||||
"permanent": true
|
||||
},
|
||||
|
@@ -12,18 +12,16 @@ import (
|
||||
)
|
||||
|
||||
// ResponseCondition is a retry condition function.
|
||||
// It receives a response, and returns an error
|
||||
// if the response failed the condition.
|
||||
// It receives a response, and returns an error if the response failed the condition.
|
||||
type ResponseCondition func(*http.Response) error
|
||||
|
||||
// BodyContains returns a retry condition function.
|
||||
// The condition returns an error if the request body does not contain all the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body does not contain all the given strings.
|
||||
func BodyContains(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
@@ -36,13 +34,12 @@ func BodyContains(values ...string) ResponseCondition {
|
||||
}
|
||||
|
||||
// BodyNotContains returns a retry condition function.
|
||||
// The condition returns an error if the request body contain one of the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body contain one of the given strings.
|
||||
func BodyNotContains(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
@@ -55,13 +52,12 @@ func BodyNotContains(values ...string) ResponseCondition {
|
||||
}
|
||||
|
||||
// BodyContainsOr returns a retry condition function.
|
||||
// The condition returns an error if the request body does not contain one of the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body does not contain one of the given strings.
|
||||
func BodyContainsOr(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
@@ -79,7 +75,7 @@ func HasBody() ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if len(body) == 0 {
|
||||
@@ -182,11 +178,11 @@ func HasHeaderStruct(header http.Header) ResponseCondition {
|
||||
}
|
||||
|
||||
// DoCondition is a retry condition function.
|
||||
// It returns an error
|
||||
// It returns an error.
|
||||
type DoCondition func() error
|
||||
|
||||
// KVExists is a retry condition function.
|
||||
// Verify if a Key exists in the store
|
||||
// Verify if a Key exists in the store.
|
||||
func KVExists(kv store.Store, key string) DoCondition {
|
||||
return func() error {
|
||||
_, err := kv.Exists(key, nil)
|
||||
|
@@ -115,7 +115,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
|
||||
select {
|
||||
case <-stopTimer.C:
|
||||
fmt.Println("-")
|
||||
return fmt.Errorf("try operation failed: %s", err)
|
||||
return fmt.Errorf("try operation failed: %w", err)
|
||||
case <-retryTick.C:
|
||||
fmt.Print("*")
|
||||
if err = operation(); err == nil {
|
||||
|
@@ -18,11 +18,11 @@ import (
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
// WebsocketSuite
|
||||
// WebsocketSuite tests suite.
|
||||
type WebsocketSuite struct{ BaseSuite }
|
||||
|
||||
func (s *WebsocketSuite) TestBase(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -72,7 +72,7 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -122,7 +122,7 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
|
||||
|
||||
func (s *WebsocketSuite) TestOrigin(c *check.C) {
|
||||
// use default options
|
||||
var upgrader = gorillawebsocket.Upgrader{}
|
||||
upgrader := gorillawebsocket.Upgrader{}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -180,7 +180,7 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
|
||||
upgrader := gorillawebsocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
}}
|
||||
|
||||
@@ -240,7 +240,7 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -297,11 +297,10 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -390,7 +389,7 @@ func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Assert(r.URL.EscapedPath(), check.Equals, "/ws/http%3A%2F%2Ftest")
|
||||
@@ -441,7 +440,7 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -504,7 +503,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
|
||||
}
|
||||
|
||||
func (s *WebsocketSuite) TestHeaderAreForwared(c *check.C) {
|
||||
var upgrader = gorillawebsocket.Upgrader{} // use default options
|
||||
upgrader := gorillawebsocket.Upgrader{} // use default options
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Assert(r.Header.Get("X-Token"), check.Equals, "my-token")
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Zk test suites (using libcompose)
|
||||
// Zk test suites (using libcompose).
|
||||
type ZookeeperSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
@@ -138,7 +138,7 @@ func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
|
||||
expectedJSON := filepath.FromSlash("testdata/rawdata-zk.json")
|
||||
|
||||
if *updateExpected {
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0666)
|
||||
err = ioutil.WriteFile(expectedJSON, got, 0o666)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@ func main() {
|
||||
genKVDynConfDoc("./docs/content/reference/dynamic-configuration/kv-ref.md")
|
||||
}
|
||||
|
||||
func genStaticConfDoc(outputFile string, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
||||
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
||||
logger := log.WithoutContext().WithField("file", outputFile)
|
||||
|
||||
element := &static.Configuration{}
|
||||
@@ -41,7 +41,7 @@ func genStaticConfDoc(outputFile string, prefix string, encodeFn func(interface{
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ const (
|
||||
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
|
||||
)
|
||||
|
||||
// Do configuration.
|
||||
// Do sends configuration.
|
||||
func Do(baseConfig interface{}, indent bool) (string, error) {
|
||||
anomConfig, err := copystructure.Copy(baseConfig)
|
||||
if err != nil {
|
||||
@@ -120,7 +120,7 @@ func reset(field reflect.Value, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isExported return true is a struct field is exported, else false
|
||||
// isExported return true is a struct field is exported, else false.
|
||||
func isExported(f reflect.StructField) bool {
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
return false
|
||||
|
@@ -11,6 +11,7 @@ type Courgette struct {
|
||||
Ji string
|
||||
Ho string
|
||||
}
|
||||
|
||||
type Tomate struct {
|
||||
Ji string
|
||||
Ho string
|
||||
|
@@ -2,18 +2,19 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// DashboardHandler expose dashboard routes
|
||||
// DashboardHandler expose dashboard routes.
|
||||
type DashboardHandler struct {
|
||||
Assets *assetfs.AssetFS
|
||||
}
|
||||
|
||||
// Append add dashboard routes on a router
|
||||
// Append add dashboard routes on a router.
|
||||
func (g DashboardHandler) Append(router *mux.Router) {
|
||||
if g.Assets == nil {
|
||||
log.WithoutContext().Error("No assets for dashboard")
|
||||
@@ -23,11 +24,29 @@ func (g DashboardHandler) Append(router *mux.Router) {
|
||||
// Expose dashboard
|
||||
router.Methods(http.MethodGet).
|
||||
Path("/").
|
||||
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
||||
http.Redirect(response, request, request.Header.Get("X-Forwarded-Prefix")+"/dashboard/", http.StatusFound)
|
||||
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(resp, req, safePrefix(req)+"/dashboard/", http.StatusFound)
|
||||
})
|
||||
|
||||
router.Methods(http.MethodGet).
|
||||
PathPrefix("/dashboard/").
|
||||
Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets)))
|
||||
}
|
||||
|
||||
func safePrefix(req *http.Request) string {
|
||||
prefix := req.Header.Get("X-Forwarded-Prefix")
|
||||
if prefix == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
parse, err := url.Parse(prefix)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if parse.Host != "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return parse.Path
|
||||
}
|
||||
|
54
pkg/api/dashboard_test.go
Normal file
54
pkg/api/dashboard_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_safePrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "host",
|
||||
value: "https://example.com",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "host with path",
|
||||
value: "https://example.com/foo/bar?test",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "path",
|
||||
value: "/foo/bar",
|
||||
expected: "/foo/bar",
|
||||
},
|
||||
{
|
||||
desc: "path without leading slash",
|
||||
value: "foo/bar",
|
||||
expected: "foo/bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://localhost", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("X-Forwarded-Prefix", test.value)
|
||||
|
||||
prefix := safePrefix(req)
|
||||
|
||||
assert.Equal(t, test.expected, prefix)
|
||||
})
|
||||
}
|
||||
}
|
@@ -19,10 +19,10 @@ func goroutines() interface{} {
|
||||
return runtime.NumGoroutine()
|
||||
}
|
||||
|
||||
// DebugHandler expose debug routes
|
||||
// DebugHandler expose debug routes.
|
||||
type DebugHandler struct{}
|
||||
|
||||
// Append add debug routes on a router
|
||||
// Append add debug routes on a router.
|
||||
func (g DebugHandler) Append(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).Path("/debug/vars").
|
||||
HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
|
@@ -55,7 +55,7 @@ type Handler struct {
|
||||
runtimeConfiguration *runtime.Configuration
|
||||
}
|
||||
|
||||
// NewBuilder returns a http.Handler builder based on runtime.Configuration
|
||||
// NewBuilder returns a http.Handler builder based on runtime.Configuration.
|
||||
func NewBuilder(staticConfig static.Configuration) func(*runtime.Configuration) http.Handler {
|
||||
return func(configuration *runtime.Configuration) http.Handler {
|
||||
return New(staticConfig, configuration).createRouter()
|
||||
|
@@ -226,7 +226,7 @@ func TestHandler_EntryPoints(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(results, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -840,7 +840,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(results, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -277,7 +277,7 @@ func TestHandler_Overview(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(results, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -548,7 +548,7 @@ func TestHandler_TCP(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(results, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -161,7 +161,7 @@ func TestHandler_RawData(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.json, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.json, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -525,7 +525,7 @@ func TestHandler_UDP(t *testing.T) {
|
||||
newJSON, err := json.MarshalIndent(results, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0644)
|
||||
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// Calls command without args.
|
||||
if len(args) == 1 {
|
||||
if err := run(cmd, args[1:]); err != nil {
|
||||
return fmt.Errorf("command %s error: %v", args[0], err)
|
||||
return fmt.Errorf("command %s error: %w", args[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// then we run the top level command itself.
|
||||
if root && cmd.Name != args[1] && !contains(cmd.subCommands, args[1]) {
|
||||
if err := run(cmd, args[1:]); err != nil {
|
||||
return fmt.Errorf("command %s error: %v", filepath.Base(args[0]), err)
|
||||
return fmt.Errorf("command %s error: %w", filepath.Base(args[0]), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
if len(args) >= 2 && cmd.Name == args[1] {
|
||||
if len(args) < 3 || !contains(cmd.subCommands, args[2]) {
|
||||
if err := run(cmd, args[2:]); err != nil {
|
||||
return fmt.Errorf("command %s error: %v", cmd.Name, err)
|
||||
return fmt.Errorf("command %s error: %w", cmd.Name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// No sub-command, calls the current command.
|
||||
if len(cmd.subCommands) == 0 {
|
||||
if err := run(cmd, args[1:]); err != nil {
|
||||
return fmt.Errorf("command %s error: %v", cmd.Name, err)
|
||||
return fmt.Errorf("command %s error: %w", cmd.Name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ func (e *EnvLoader) Load(_ []string, cmd *Command) (bool, error) {
|
||||
|
||||
if err := env.Decode(vars, env.DefaultNamePrefix, cmd.Configuration); err != nil {
|
||||
log.WithoutContext().Debug("environment variables", strings.Join(vars, ", "))
|
||||
return false, fmt.Errorf("failed to decode configuration from environment variables: %v ", err)
|
||||
return false, fmt.Errorf("failed to decode configuration from environment variables: %w ", err)
|
||||
}
|
||||
|
||||
log.WithoutContext().Println("Configuration loaded from environment variables.")
|
||||
|
@@ -17,7 +17,7 @@ func (*FlagLoader) Load(args []string, cmd *Command) (bool, error) {
|
||||
}
|
||||
|
||||
if err := flag.Decode(args, cmd.Configuration); err != nil {
|
||||
return false, fmt.Errorf("failed to decode configuration from flags: %v", err)
|
||||
return false, fmt.Errorf("failed to decode configuration from flags: %w", err)
|
||||
}
|
||||
|
||||
log.WithoutContext().Println("Configuration loaded from flags.")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user