1
0
mirror of https://github.com/containous/traefik.git synced 2025-10-03 01:44:23 +03:00

Compare commits

...

240 Commits

Author SHA1 Message Date
NicoMen
a1911a9608 Prepare release 1.7.0 rc2 2018-07-17 14:30:03 +02:00
Michael
ff2e2d5026 Fix 400 bad request on AWS ECS API 2018-07-17 12:26:03 +02:00
Ludovic Fernandez
a953d3ad89 Auth section in web UI. 2018-07-17 12:02:03 +02:00
Jean-Baptiste Doumenjou
9ce444b91a Don't pass the Authorization header to the backends 2018-07-16 13:52:03 +02:00
Fernandez Ludovic
ae8be89767 Merge branch 'v1.6' into 'v1.7' 2018-07-13 18:06:07 +02:00
SALLEYRON Julien
5774d100c1 Update service fabric 2018-07-13 18:04:03 +02:00
Daniel Tomcej
dbe720f0f1 Remove unusable --cluster flag 2018-07-13 17:32:03 +02:00
Ludovic Fernandez
5afc8f2b12 KV and authentication 2018-07-13 17:24:03 +02:00
Fernandez Ludovic
c7e008f57a Merge branch 'v1.6' into 'v1.7' 2018-07-12 19:24:11 +02:00
NicoMen
14b7152bf0 Serve TLS-Challenge certificate in first 2018-07-12 19:10:03 +02:00
Damien Duportal
3ef6bf2118 Documentation: Introduces a check stage to validate HTML and links 2018-07-12 18:26:03 +02:00
Jonathan Ballet
f0ab2721a5 Fix path to the debug pprof API 2018-07-12 17:58:02 +02:00
Daniel Tomcej
2721c2017c Correct Modifier in Kubernetes Documentation 2018-07-12 17:42:05 +02:00
Michael
a7c158f0e1 Fix bad condition in ECS provider 2018-07-12 17:40:04 +02:00
Daniel Tomcej
7ff9193cf5 Correct App-Root kubernetes behavior 2018-07-12 15:20:04 +02:00
Fernandez Ludovic
031451abab Merge branch 'v1.6.5' into 'v1.7' 2018-07-11 11:07:42 +02:00
Ludovic Fernandez
8d75aba7eb Send 'Retry-After' to comply with RFC6585. 2018-07-11 10:08:03 +02:00
SALLEYRON Julien
027093a5a5 Create init method on provider interface 2018-07-11 09:08:03 +02:00
Ludovic Fernandez
bdc0e3bfcf Prepare release v1.6.5 2018-07-10 17:46:04 +02:00
Daniel Tomcej
b2a57ca1f3 Add more K8s Unit Tests 2018-07-10 11:22:03 +02:00
Fernandez Ludovic
6ef0e6791b Merge branch 'v1.6' into 'v1.7' 2018-07-10 01:24:14 +02:00
Daniel Tomcej
9374d6b3b9 Fix rewrite-target Annotation behavior 2018-07-10 00:26:03 +02:00
SALLEYRON Julien
f173ff02e3 Add a mutex on local store for HTTPChallenges 2018-07-09 23:28:02 +02:00
Michael
ba2046491a Prepare release 1.7.0-rc1 2018-07-09 16:54:04 +02:00
Fernandez Ludovic
083b471bcf Merge branch 'v1.6' into master 2018-07-09 15:34:47 +02:00
Shane Smith-Sahnow
bf73127e0b Performance enhancements for the rules matchers. 2018-07-09 15:08:04 +02:00
SALLEYRON Julien
333b785061 Add logs when error is generated in error handler 2018-07-07 10:14:03 +02:00
Jean-Baptiste Doumenjou
79bf19c897 Auth support in frontends 2018-07-06 16:52:04 +02:00
Timo Reimann
0c0ecc1cdc Call functions to enable block/mutex pprof profiles. 2018-07-06 10:58:04 +02:00
SALLEYRON Julien
bacd58ed7b Add logs when error is generated in error handler 2018-07-06 10:32:03 +02:00
Daniel Tomcej
689f120410 Improve TLS Handshake 2018-07-06 10:30:03 +02:00
Daniel Tomcej
2303301d38 Add annotation to allow modifiers to be used properly in kubernetes 2018-07-06 10:06:04 +02:00
Or Tzabary
f323df466d Split the error handling from Consul Catalog (deadlock) 2018-07-05 15:12:03 +02:00
Kim Min
b1f1a5b757 Substitude hardcoded "<namespace>/<name>" with k8s ListerGetter 2018-07-04 17:08:03 +02:00
Andrew Stucki
0d262561d1 Allow binding ECS container port 2018-07-04 15:08:03 +02:00
hwhelan-CB
12c713b187 Support traefik.backend for ECS 2018-07-04 14:22:03 +02:00
Fabian Beuke
b1836587f2 Update keyFile first/last line comment in kv-config.md 2018-07-04 14:20:03 +02:00
Trevin Teacutter
04d8b5d483 Adding compatibility for marathon 1.5 2018-07-03 23:42:03 +02:00
Daniel Tomcej
461ebf6d88 Create Global Backend Ingress 2018-07-03 18:58:03 +02:00
Timo Reimann
41eb4f1c70 Add a k8s guide section on traffic splitting via service weights. 2018-07-03 16:50:06 +02:00
Gamalan
31a8e3e39a CNAME flattening 2018-07-03 16:44:05 +02:00
Ludovic Fernandez
139f280f35 ACME TLS ALPN 2018-07-03 12:44:04 +02:00
Ludovic Fernandez
17ad5153b8 Minor changes 2018-07-03 10:02:03 +02:00
Mikael Rapp
bb14ec70bd Auth support in frontends for k8s and file 2018-07-02 11:52:04 +02:00
Kim Min
e8e36bd9d5 Specify backend servers' weight via annotation for kubernetes 2018-07-01 11:26:03 +02:00
hwhelan-CB
f9b1106df2 Forward auth headers 2018-06-30 07:54:03 +02:00
Fernandez Ludovic
df600d6f3c Merge branch 'v1.6' into master 2018-06-30 00:43:32 +02:00
Andrew Stucki
157e76e829 Add support for ECS constraints 2018-06-30 00:14:03 +02:00
John Yani
dbc3b85cd0 Minor formatting issue in user-guide 2018-06-29 17:02:03 +02:00
Drew G. Wallace
11691019a0 Change code block of traefik-web-ui to match file 2018-06-28 23:10:03 +02:00
Alex Antonov
3192307d59 Added integration support for DataDog APM Tracing 2018-06-28 18:40:04 +02:00
Michael
ba8c9295ac Update golang.org/x/net dependency 2018-06-28 17:58:04 +02:00
Michael
d5436fb28b Create a custom logger for jaeger 2018-06-28 17:36:03 +02:00
Michael Arenzon
886cc83ad9 Add support for stale reads from Consul catalog 2018-06-28 16:40:04 +02:00
Ludovic Fernandez
9e012a6b54 Simplify acme e2e tests. 2018-06-27 15:08:05 +02:00
Jean-Baptiste Doumenjou
5eda08e9b8 Better support on same prefix at the same level in the KV 2018-06-26 16:18:05 +02:00
Ludovic Fernandez
ec6e46e2cb segment labels: multiple frontends for one backend. 2018-06-22 19:44:03 +02:00
Rene Treffer
56fe023a12 Allow any kubernetes ingressClass value 2018-06-22 16:54:03 +02:00
Michael
aa705dd691 Create middleware to be able to handle HTTP pipelining correctly 2018-06-20 09:12:03 +02:00
Daniel Tomcej
aa6fea7f21 Add more k8s tests 2018-06-19 22:10:03 +02:00
Marco Jantke
e31c85aace avoid retries when any data was written to the backend 2018-06-19 13:56:04 +02:00
manu5801
1c3e4124f8 The gandiv5 provider works with wildcard 2018-06-18 09:26:02 +02:00
Fernandez Ludovic
586ba31120 Merge v1.6.4 into master 2018-06-15 17:58:20 +02:00
Ludovic Fernandez
c1757372d3 Prepare release v1.6.4 2018-06-15 17:04:03 +02:00
Ludovic Fernandez
7451449dd6 Simplify get acme client 2018-06-15 16:42:03 +02:00
Ludovic Fernandez
5b2b29043c Use logrus writer instead of os.Stderr 2018-06-15 16:08:03 +02:00
Daniel Tomcej
2758664226 Fix panic setting ingress status 2018-06-14 09:22:03 +02:00
Ludovic Fernandez
bb3f28ffa7 Backend name with docker-compose and segments. 2018-06-14 09:20:04 +02:00
Ludovic Fernandez
6ceb2af4a7 Clean metrics documentation. 2018-06-13 17:44:04 +02:00
erik-sjoestedt
d5b649bf1c Add xforwarded method 2018-06-13 15:14:03 +02:00
Jean-Baptiste Doumenjou
81f23cc732 Add a default value for the docker.network configuration 2018-06-13 14:50:04 +02:00
Ludovic Fernandez
b59276ff1c Use net.JoinHostPort for servers URL 2018-06-13 10:08:03 +02:00
herver
2e95832812 Enclose IPv6 addresses in "[]" 2018-06-13 08:06:03 +02:00
Ludovic Fernandez
01f2b3cd20 Update Slack URL. 2018-06-12 17:04:04 +02:00
Yoan Blanc
2240bf9430 The exoscale provider works with wildcard 2018-06-12 16:16:03 +02:00
Shambarick
db036edccd Fix typo in kv user guide 2018-06-12 08:20:03 +02:00
Rodrigo Díez Villamuera
1fbf5b84a2 Added duration filter for logs 2018-06-11 18:40:08 +02:00
Mayank Jethva
08e1f626c1 edit wording 2018-06-11 16:26:03 +02:00
Emile Vauge
c0d08f5e3e Temporary benchmarks removal during performance optimization process 2018-06-11 11:46:03 +02:00
Ludovic Fernandez
eac20d61df Extreme Makeover: server refactoring 2018-06-11 11:36:03 +02:00
Ludovic Fernandez
dec3f0798a Add missing annotation documentation. 2018-06-08 12:54:02 +02:00
Fernandez Ludovic
bddb4cc33c Merge branch 'v1.6' into master 2018-06-07 10:58:59 +02:00
SALLEYRON Julien
62ded580ce Handle buffer pool for oxy 2018-06-07 09:46:03 +02:00
Arne Jørgensen
51227241b7 Fix backend reuse 2018-06-06 17:56:03 +02:00
Geert-Johan Riemer
9cf4e730e7 Fix typo which breaks k8s example manifest 2018-06-06 17:16:04 +02:00
Ludovic Fernandez
e9c63f3988 Custom frontend name for test helper 2018-06-06 15:20:03 +02:00
Pierre Mavro
2c47691cf1 Adding grafana dashboards based on prometheus metrics 2018-06-06 14:54:03 +02:00
Drew Kerrigan
599b699ac9 Segments Labels: Mesos 2018-06-06 00:26:03 +02:00
Fernandez Ludovic
a5beeb4f04 Merge tag 'v1.6.3' into master 2018-06-05 23:07:53 +02:00
Michael
446d73fcf5 Prepare release v1.6.3 2018-06-05 17:20:04 +02:00
Michael
e299775d67 Detect change when service or node are in maintenance mode 2018-06-05 16:42:03 +02:00
Marco Jantke
2c18750537 Improve Prometheus metrics removal 2018-06-05 12:32:03 +02:00
Jonas Thelemann
f317e50136 Docs: ACME Overhaul 2018-06-05 10:36:03 +02:00
Daniel Tomcej
1d84bda7ca Update Kubernetes provider to support IPv6 Backends 2018-06-05 10:28:03 +02:00
Ludovic Fernandez
ae7c947ba5 Add user agent for ACME 2018-06-05 09:54:03 +02:00
Ludovic Fernandez
6d07729c55 Add URL and Host for some access logs. 2018-06-05 09:02:03 +02:00
The Binary
1d7bf200a8 Reflect changes in catalog healthy nodes in healthCheck watch 2018-06-05 08:42:03 +02:00
Gérald Croës
6bc59f8b33 Includes the headers in the HTTP response of a websocket request 2018-06-04 14:14:03 +02:00
Ludovic Fernandez
b2cf03fa5c Use to the stable version of Lego 2018-05-31 09:30:04 +02:00
Erik Aulin
36e273714d helm installation using values 2018-05-30 17:38:04 +02:00
Ludovic Fernandez
6be77b7fb9 Webui Whitelist overflow. 2018-05-30 09:44:02 +02:00
Ludovic Fernandez
6bcf45f136 fix: whitelist and XFF. 2018-05-30 09:26:03 +02:00
Amin Cheloh
8bca8236db Update acme.md 2018-05-30 04:16:03 +02:00
Drew Kerrigan
67a0b4b4b1 Metrics: Add support for InfluxDB Database / RetentionPolicy and HTTP client 2018-05-29 22:58:03 +02:00
Michael
a7200a292b AWS ECS Fargate 2018-05-28 18:52:03 +02:00
Ludovic Fernandez
fb5aa4c9c1 Error pages and header merge 2018-05-28 15:00:04 +02:00
NicoMen
3f5772c62a Improve ACME account registration URI management 2018-05-28 14:40:03 +02:00
SALLEYRON Julien
e76836b948 h2c server 2018-05-28 11:46:03 +02:00
NicoMen
2d946d7ee7 Remove ACME empty certificates from KV store 2018-05-25 19:36:04 +02:00
Daniel Tomcej
10ca35dccd Update Kubernetes Port Documentation 2018-05-25 17:26:05 +02:00
SALLEYRON Julien
bfdd1997f6 Generated assets file are only mandatory in main 2018-05-25 15:10:04 +02:00
SALLEYRON Julien
9420308667 Implement h2c with backend 2018-05-24 10:52:04 +02:00
Ingo Gottwald
83e09acc9f Upgrade dependencies 2018-05-23 17:48:04 +02:00
Ondrej Flidr
d6d795e286 Support 3xx HTTP status codes for health check 2018-05-23 17:06:04 +02:00
ryarnyah
c09febfffc Make accesslogs.logTheRoundTrip async to get lost performance 2018-05-23 16:46:04 +02:00
Ludovic Fernandez
5b3bba8f6e Add missing quotes. 2018-05-23 16:12:05 +02:00
Marco Jantke
085593b9e5 sane default and configurable Marathon request timeouts 2018-05-22 22:38:03 +02:00
Fernandez Ludovic
e2a5d4f83e Merge 'v1.6.2' into master 2018-05-22 19:14:34 +02:00
SALLEYRON Julien
e3671cbb04 Prepare release 1.6.2 2018-05-22 17:06:04 +02:00
Ludovic Fernandez
a525d02cc5 Force to use ACME v02 endpoint. 2018-05-22 16:08:03 +02:00
Ludovic Fernandez
3c8c5ebb96 Use index-based syntax in KV tests. 2018-05-22 12:30:03 +02:00
Ludovic Fernandez
1cc1a4e6e2 WebUI typo into the buffering section. 2018-05-22 12:28:03 +02:00
SALLEYRON Julien
3f0af3fe09 No template parsing on traefik configuration file 2018-05-22 12:02:03 +02:00
Ludovic Fernandez
e2bac47a0a Support all 2xx HTTP status code for health check. 2018-05-22 09:22:03 +02:00
Ludovic Fernandez
bc26d9f0de Enhance Load-balancing method validation log. 2018-05-22 09:20:03 +02:00
Daniel Tomcej
5c4692a0df Modify tests to only run if non-static files have been modified 2018-05-19 00:30:03 +02:00
Florian Woerner
0ba28bbc8b Update caServer to letsencrypt one in examples 2018-05-18 18:16:03 +02:00
Michael Ermer
550184275a Add basicAuth example for KV 2018-05-18 17:54:03 +02:00
DeamonMV
c376083ecb Add command for basic auth with Docker Compose 2018-05-18 17:34:04 +02:00
Ludovic Fernandez
1db5fcf200 Removes ambiguity with the word 'default' 2018-05-18 17:12:03 +02:00
Ludovic Fernandez
16b2555ab3 Fix error pages content. 2018-05-18 16:38:03 +02:00
Daniel Tomcej
9227d32d57 Enable Ingress Status updates 2018-05-18 14:12:03 +02:00
Gildas Cherruel
c37b040217 Mapping ExternalNames to custom ports 2018-05-17 18:46:03 +02:00
Ingo Gottwald
5a1d2aa4b6 Fix contributing guide link in PR template 2018-05-17 12:52:03 +02:00
Thomas Fan
4a3b1f3847 Enable to override certificates in key-value store when using storeconfig 2018-05-17 12:32:03 +02:00
Joni Collinge
d9a5258f40 Update docs to match SF provider labels 2018-05-17 11:04:03 +02:00
Daniel Tomcej
190ebbed27 Update docs to reflect Provider wording 2018-05-16 19:48:03 +02:00
Ludovic Fernandez
a0872c9e31 Route rules overlaps in UI 2018-05-16 13:44:03 +02:00
Michael
68cc826519 Add option to select algorithm to generate ACME certificates 2018-05-16 11:44:03 +02:00
Daniel Tomcej
f5b306e7ff Add redirect-permanent to kubernetes template 2018-05-16 10:46:03 +02:00
Ludovic Fernandez
7a1feb3c51 fix: acme errors management. 2018-05-15 17:28:02 +02:00
Ludovic Fernandez
e691168cdc Add some missing elements in the WebUI 2018-05-15 17:26:04 +02:00
Fernandez Ludovic
4eda1e1bd4 Merge branch 'v1.6' into master 2018-05-15 10:43:27 +02:00
Ludovic Fernandez
1e8df9f245 Prepare release v1.6.1 2018-05-14 21:08:03 +02:00
Ludovic Fernandez
b72937e8fb Fix webui 2018-05-14 19:46:03 +02:00
Ludovic Fernandez
df11e67bb4 Override health check scheme 2018-05-14 12:08:03 +02:00
Ludovic Fernandez
b7d20496f3 Add SSLForceHost support. 2018-05-14 11:44:03 +02:00
Ludovic Fernandez
67847c3117 Error when accesslog and error pages 2018-05-14 10:38:03 +02:00
Ludovic Fernandez
a2a0c80acb Fix segment backend name 2018-05-14 10:18:03 +02:00
Ludovic Fernandez
b3fd06fb45 Add missing deprecation info in CLI help. 2018-05-14 09:52:03 +02:00
Ludovic Fernandez
c5db8d903c Enhance entry point TLS CLI reference. 2018-05-13 17:12:03 +02:00
Daniel Tomcej
8fcd242494 Add Documentation update for Kubernetes Ingress 2018-05-11 12:52:03 +02:00
Blake Patton
ebd9af900e Changed "is could" to should 2018-05-09 17:48:03 +02:00
Michael
b02381c2d5 Fix wrong tag in forward span in tracing middleware 2018-05-08 12:00:03 +02:00
Ludovic Fernandez
dce65ab9c2 Restore default issue template. 2018-05-07 14:16:02 +02:00
Ludovic Fernandez
97295f270b Update issue templates 2018-05-07 12:14:02 +02:00
Fernandez Ludovic
8e64bc8785 Merge branch 'v1.6' into master 2018-05-04 17:57:06 +02:00
Ludovic Fernandez
9b199ea756 fix: 1.6 change log. 2018-05-04 16:08:03 +02:00
Ludovic Fernandez
ec3b913ee4 fix: change log v1.6.0 2018-05-01 00:46:03 +02:00
SALLEYRON Julien
c210ab31d9 Prepare release v1.6.0 2018-04-30 23:20:05 +02:00
Timo Reimann
6c1fa91c70 Document custom k8s ingress class usage in guide. 2018-04-30 20:28:03 +02:00
Ludovic Fernandez
04bab185f6 Add redirect section. 2018-04-30 12:28:03 +02:00
Ludovic Fernandez
2213b4cf37 Cleaning labels/annotations documentation. 2018-04-30 12:08:03 +02:00
Alexy Mikhailichenko
1d770e5636 Fix typo and tweak formatting in quickstart 2018-04-30 09:24:04 +02:00
Ludovic Fernandez
b7e15e0a2c doc: update Traefik images. 2018-04-27 14:54:03 +02:00
Jan Kuri
9c651ae913 New web ui 2018-04-27 13:12:04 +02:00
SALLEYRON Julien
a1bbaec71f Does not generate ACME certificate if domain is checked by dynamic certificate 2018-04-27 10:36:04 +02:00
Fernandez Ludovic
3b3ca89483 Merge branch 'v1.6' into master 2018-04-25 08:22:17 +02:00
SALLEYRON Julien
b4e3bca6fa Remove acme provider dependency in server 2018-04-24 22:40:04 +02:00
Michael
e09d5cb4ec Fix documentation for tracing with Jaeger 2018-04-24 19:22:03 +02:00
NicoMen
cae353b9f6 Add documentation about Templating in backend file 2018-04-24 18:58:03 +02:00
Ludovic Fernandez
edb5b3d711 Fix whitelist and XFF. 2018-04-23 16:20:05 +02:00
Colin Coller
667a0c41ed Minor improvements to documentation 2018-04-23 15:56:03 +02:00
SALLEYRON Julien
9daae9c705 Extract internal router creation from server 2018-04-23 15:30:03 +02:00
Ludovic Fernandez
2975acdc82 Forward auth: copy response headers when auth failed. 2018-04-23 15:28:04 +02:00
Ludovic Fernandez
76dcbe3429 Fix error pages redirect and headers. 2018-04-23 11:28:04 +02:00
Ludovic Fernandez
d8e2d464ad Remove dead code. 2018-04-23 10:54:03 +02:00
Arnas
5f8bcb0c26 Fix typo in documentation 2018-04-23 10:28:04 +02:00
Ludovic Fernandez
7ef8d6fa10 Ignore server for container with empty IP address. 2018-04-22 09:10:03 +02:00
Fernandez Ludovic
5924a40222 Fix Service Fabric docs to use v1.6 labels. 2018-04-19 20:15:20 +02:00
Joni Collinge
05968eb232 Fix Service Fabric docs to use v1.6 labels
Fix docs to use v1.6 labels rather than v1.5.
2018-04-19 16:30:10 +02:00
Ludovic Fernandez
36dcfbfe2d Add HTTP headers to healthcheck. 2018-04-18 18:16:03 +02:00
Fernandez Ludovic
95ce4f5c1e refactor: minor fixes. 2018-04-18 10:48:03 +02:00
Fernandez Ludovic
f258f20b04 doc: add 'traefik.domain'. 2018-04-18 10:48:03 +02:00
Fernandez Ludovic
7e2ad827aa fix: used 'traefik.domain' in frontend rule. 2018-04-18 10:48:03 +02:00
Fernandez Ludovic
e6ce61fdf0 Merge tag 'v1.6.0-rc6' into master 2018-04-18 10:13:22 +02:00
Michael
3df588047d Prepare release v1.6.0-rc6 2018-04-17 13:42:03 +02:00
Ludovic Fernandez
ac0e5cbb29 Use shared label system 2018-04-17 11:18:04 +02:00
Michael
5ab584bc6a Fix panic in atomic on ARM and x86-32 platforms 2018-04-17 10:32:03 +02:00
NicoMen
a2e03e3bd0 Create backup file during migration from ACME V1 to ACME V2 2018-04-16 19:34:04 +02:00
Jean-Baptiste Doumenjou
f0589b310f Fix multiple frontends with docker-compose --scale 2018-04-16 18:14:04 +02:00
Michael
8519b0d353 Fix nil value when tracing is enabled 2018-04-16 17:42:03 +02:00
Timo Reimann
21b8b2deb5 Support multi-port services. 2018-04-16 14:44:04 +02:00
Alex Antonov
6b82a77e36 Improved cluster api to include the current leader node 2018-04-16 14:10:04 +02:00
Jesse Haka
1954a49f37 add http headers to healthcheck 2018-04-16 11:40:03 +02:00
Manuel Zapf
0e3d1e1503 fix: redirect to HTTPS first before basic auth if header redirect (secure) is set 2018-04-16 11:06:03 +02:00
Michael
ebd77f314d Fix duplicated tags in InfluxDB 2018-04-16 10:28:04 +02:00
Ludovic Fernandez
749d833f65 fix: template version documentation. 2018-04-16 00:34:03 +02:00
Cyrille Hemidy
0373cd6f97 Add missing argument in log. 2018-04-13 19:46:03 +02:00
Ludovic Fernandez
1f3fc8a366 fix: backend name for stateful service and more. 2018-04-13 15:44:04 +02:00
Fernandez Ludovic
89c3930b28 Merge branch 'v1.5' into 'v1.6' 2018-04-13 15:02:29 +02:00
Ludovic Fernandez
29e1e9eef2 fix: backend name for stateful service. 2018-04-13 14:38:03 +02:00
Fernandez Ludovic
de3aeb9732 Merge branch 'v1.6' into mrg-current-v1.6 2018-04-12 14:36:36 +02:00
SALLEYRON Julien
85aa1a444a Prepare release 1.6.0-rc5 2018-04-12 11:44:03 +02:00
Timo Reimann
702876ae7f Limit label selector to Ingress factory. 2018-04-12 11:14:05 +02:00
NicoMen
7109910f46 Generate wildcard certificate with SANs in ACME 2018-04-11 17:16:07 +02:00
Ludovic Fernandez
8168d2fdc1 Server weight zero 2018-04-11 16:30:04 +02:00
Fernandez Ludovic
edbcd01fbc Merge branch 'v1.5' into 'v1.6' 2018-04-11 14:20:53 +02:00
Ludovic Fernandez
c99266e961 Fix: error pages 2018-04-11 13:54:03 +02:00
Ludovic Fernandez
f804053736 Factorize labels managements. 2018-04-11 12:26:03 +02:00
Manuel Zapf
2641832304 Default certificate expiry 2018-04-11 10:36:03 +02:00
Andrey Fedoseev
21f6f81914 Update kubernetes.md 2018-04-11 10:34:04 +02:00
Emile Vauge
ccd919aba3 Fix Azure brand 2018-04-10 17:26:04 +02:00
SALLEYRON Julien
2387010556 Disable closeNotify when method GET for http pipelining 2018-04-10 17:24:04 +02:00
Jack Twilley
f35d574759 Minor updates to dumpcerts.sh 2018-04-10 16:52:05 +02:00
NicoMen
3be74bb275 Fix acme.json file automatic creation 2018-04-10 10:52:04 +02:00
Ludovic Fernandez
b1be062437 fix: update lego. 2018-04-09 18:28:03 +02:00
Ludovic Fernandez
2d0d320d05 Remove useless ACME tab from UI. 2018-04-09 16:06:03 +02:00
Jakub Piasecki
1de5111ab5 s/Host/HostRegexp 2018-04-09 11:18:03 +02:00
Ludovic Fernandez
3d530e4747 Command version explanation for alpine image. 2018-04-06 18:14:03 +02:00
Ludovic Fernandez
0ef1b7b683 Fix: Add TTL and custom Timeout in DigitalOcean DNS provider 2018-04-06 17:04:03 +02:00
Alexander Kachkaev
66485e81b4 Normalize parameter names in configs 2018-04-06 09:38:03 +02:00
NicoMen
e74e7cf734 Add ACME certificates only on ACME EntryPoint 2018-04-06 08:44:03 +02:00
Fernandez Ludovic
03ce6a1cc4 Merge tag 'v1.6.0-rc4' into master 2018-04-04 15:10:03 +02:00
Ludovic Fernandez
a19b93c966 fix: overflow on 32 bits arch. 2018-04-04 15:04:04 +02:00
Ludovic Fernandez
f7fd1f2a63 Prepare release v1.6.0-rc4 2018-04-04 14:12:03 +02:00
Ludovic Fernandez
88b71d23db Several apps with same backend name in Marathon. 2018-04-04 12:28:03 +02:00
Ludovic Fernandez
762ef12eb6 Support TLS MinVersion and CipherSuite as CLI option. 2018-04-04 11:56:04 +02:00
Fernandez Ludovic
6845068b82 doc: template version for ECS, Consul Catalog and Mesos. 2018-04-04 11:52:05 +02:00
Fernandez Ludovic
5c0b18efe4 chore: autogen. 2018-04-04 11:52:05 +02:00
Fernandez Ludovic
4b93d040b3 refactor: Mesos labels. 2018-04-04 11:52:05 +02:00
Fernandez Ludovic
ff61cc971e refactor: Consul Catalog labels. 2018-04-04 11:52:05 +02:00
Fernandez Ludovic
46db91ce73 refactor: ECS labels. 2018-04-04 11:52:05 +02:00
Ludovic Fernandez
5921909ef5 Add tests on IPWhiteLister. 2018-04-03 18:36:03 +02:00
Fernandez Ludovic
1537861c61 Merge branch 'v1.5' into 'v1.6' 2018-04-03 12:12:19 +02:00
jakeprem
1b93551572 Update docker-and-lets-encrypt example to show traefik:1.5.4 2018-04-03 11:14:04 +02:00
Rodrigo
197a5fbcf4 Update kubernetes.md 2018-04-03 10:30:03 +02:00
Alex Antonov
ff32529345 Moved /api/cluster/leadership handler under public routes (requires no authentication) 2018-04-03 10:00:07 +02:00
Ludovic Fernandez
a179c3b399 Fixes prefixed annotations support. 2018-04-03 09:40:04 +02:00
Emir Karşıyakalı
a820585f56 Fixed documentation urls on README.md 2018-03-30 11:18:03 +02:00
1263 changed files with 176251 additions and 72155 deletions

3
.gitattributes vendored
View File

@@ -1,2 +1 @@
vendor/github.com/xenolf/lego/providers/dns/cloudxns/cloudxns.go eol=crlf
# vendor/github.com/xenolf/lego/providers/dns/cloudxns/cloudxns.go eol=crlf

View File

@@ -2,10 +2,10 @@
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, refer to one of the following:
For end-user related support questions, please refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://traefik.herokuapp.com
- the Traefik community Slack channel: https://slack.traefik.io
-->
@@ -23,9 +23,9 @@ If you intend to ask a support question: DO NOT FILE AN ISSUE.
HOW TO WRITE A GOOD ISSUE?
- Respect the issue template as much as possible.
- If it's possible use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- If possible, use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title should be short and descriptive.
- Explain the conditions which led you to report this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
@@ -46,6 +46,10 @@ HOW TO WRITE A GOOD ISSUE?
For the Traefik Docker image:
docker run [IMAGE] version
ex: docker run traefik version
For the alpine Traefik Docker image:
docker run [IMAGE] traefik version
ex: docker run traefik traefik version
-->
```

View File

@@ -1,68 +1,78 @@
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://traefik.herokuapp.com
-->
### Do you want to request a *feature* or report a *bug*?
Bug
### What did you do?
<!--
HOW TO WRITE A GOOD ISSUE?
- Respect the issue template as much as possible.
- If it's possible use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
### What did you expect to see?
### What did you see instead?
### Output of `traefik version`: (_What version of Traefik are you using?_)
<!--
For the Traefik Docker image:
docker run [IMAGE] version
ex: docker run traefik version
-->
```
(paste your output here)
```
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
```toml
# (paste your configuration here)
```
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output in DEBUG level (`--logLevel=DEBUG` switch)
```
(paste your output here)
```
---
name: Bug report
about: Create a report to help us improve
---
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, please refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://slack.traefik.io
-->
### Do you want to request a *feature* or report a *bug*?
Bug
### What did you do?
<!--
HOW TO WRITE A GOOD BUG REPORT?
- Respect the issue template as much as possible.
- If possible, use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title should be short and descriptive.
- Explain the conditions which led you to report this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
### What did you expect to see?
### What did you see instead?
### Output of `traefik version`: (_What version of Traefik are you using?_)
<!--
For the Traefik Docker image:
docker run [IMAGE] version
ex: docker run traefik version
For the alpine Traefik Docker image:
docker run [IMAGE] traefik version
ex: docker run traefik traefik version
-->
```
(paste your output here)
```
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
```toml
# (paste your configuration here)
```
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output in DEBUG level (`--logLevel=DEBUG` switch)
```
(paste your output here)
```

View File

@@ -1,32 +1,37 @@
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://traefik.herokuapp.com
-->
### Do you want to request a *feature* or report a *bug*?
Feature
### What did you expect to see?
<!--
HOW TO WRITE A GOOD ISSUE?
- Respect the issue template as much as possible.
- If it's possible use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
---
name: Feature request
about: Suggest an idea for this project
---
<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, please refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://slack.traefik.io
-->
### Do you want to request a *feature* or report a *bug*?
Feature
### What did you expect to see?
<!--
HOW TO WRITE A GOOD ISSUE?
- Respect the issue template as much as possible.
- If possible, use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title should be short and descriptive.
- Explain the conditions which led you to report this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->

View File

@@ -12,7 +12,7 @@ HOW TO WRITE A GOOD PULL REQUEST?
- Write useful descriptions and titles.
- Address review comments in terms of additional commits.
- Do not amend/squash existing ones unless the PR is trivial.
- Read the contributing guide: https://github.com/containous/traefik/blob/master/.github/CONTRIBUTING.md.
- Read the contributing guide: https://github.com/containous/traefik/blob/master/CONTRIBUTING.md.
-->

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@
/traefik
/traefik.toml
/static/
/webui/.tmp/
.vscode/
/site/
*.log

4
.semaphoreci/cleanup.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
sudo rm -rf static

6
.semaphoreci/job1.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
if [ -n "$SHOULD_TEST" ]; then ci_retry make pull-images; fi
if [ -n "$SHOULD_TEST" ]; then ci_retry make test-integration; fi

8
.semaphoreci/job2.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -e
ci_retry make validate
if [ -n "$SHOULD_TEST" ]; then ci_retry make test-unit; fi
if [ -n "$SHOULD_TEST" ]; then make -j${N_MAKE_JOBS} crossbinary-default-parallel; fi

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env bash
set -e
sudo -E apt-get -yq update
sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*
docker version
export DOCKER_VERSION=17.03.1
pip install --user -r requirements.txt
source .semaphoreci/vars
make pull-images
ci_retry make validate
if [ -z "${PULL_REQUEST_NUMBER}" ]; then SHOULD_TEST="-*-"; else TEMP_STORAGE=$(curl --silent https://patch-diff.githubusercontent.com/raw/containous/traefik/pull/${PULL_REQUEST_NUMBER}.diff | patch --dry-run -p1 -R); fi
if [ -n "$TEMP_STORAGE" ]; then SHOULD_TEST=$(echo "$TEMP_STORAGE" | grep -Ev '(.md|.yaml|.yml)' || :); fi
if [ -n "$SHOULD_TEST" ]; then sudo -E apt-get -yq update; fi
if [ -n "$SHOULD_TEST" ]; then sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*; fi
if [ -n "$SHOULD_TEST" ]; then docker version; fi

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -e
make test-unit
ci_retry make test-integration
make -j${N_MAKE_JOBS} crossbinary-default-parallel

View File

@@ -10,7 +10,7 @@ else
export VERSION=''
fi
export CODENAME=tetedemoine
export CODENAME=maroilles
export N_MAKE_JOBS=2

View File

@@ -11,11 +11,12 @@ env:
global:
- REPO: $TRAVIS_REPO_SLUG
- VERSION: $TRAVIS_TAG
- CODENAME: tetedemoine
- CODENAME: maroilles
- N_MAKE_JOBS: 2
script:
- echo "Skipping tests... (Tests are executed on SemaphoreCI)"
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make docs-verify; fi
before_deploy:
- >

View File

@@ -1,5 +1,448 @@
# Change Log
## [v1.7.0-rc2](https://github.com/containous/traefik/tree/v1.7.0-rc2) (2018-07-17)
[All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v1.7.0-rc2)
**Bug fixes:**
- **[acme,provider]** Create init method on provider interface ([#3580](https://github.com/containous/traefik/pull/3580) by [Juliens](https://github.com/Juliens))
- **[acme]** Serve TLS-Challenge certificate in first ([#3605](https://github.com/containous/traefik/pull/3605) by [nmengin](https://github.com/nmengin))
- **[api,authentication,webui]** Auth section in web UI. ([#3628](https://github.com/containous/traefik/pull/3628) by [ldez](https://github.com/ldez))
- **[authentication,middleware,provider]** Don&#39;t pass the Authorization header to the backends ([#3606](https://github.com/containous/traefik/pull/3606) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[ecs]** Fix 400 bad request on AWS ECS API ([#3629](https://github.com/containous/traefik/pull/3629) by [mmatur](https://github.com/mmatur))
- **[k8s]** Fix rewrite-target Annotation behavior ([#3582](https://github.com/containous/traefik/pull/3582) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Correct App-Root kubernetes behavior ([#3592](https://github.com/containous/traefik/pull/3592) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Add more K8s Unit Tests ([#3583](https://github.com/containous/traefik/pull/3583) by [dtomcej](https://github.com/dtomcej))
- **[kv]** KV and authentication ([#3615](https://github.com/containous/traefik/pull/3615) by [ldez](https://github.com/ldez))
- **[middleware]** Send &#39;Retry-After&#39; to comply with RFC6585. ([#3593](https://github.com/containous/traefik/pull/3593) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s]** Correct Modifier in Kubernetes Documentation ([#3610](https://github.com/containous/traefik/pull/3610) by [dtomcej](https://github.com/dtomcej))
**Misc:**
- Merge v1.6.5 into v1.7 ([#3595](https://github.com/containous/traefik/pull/3595) by [ldez](https://github.com/ldez))
## [v1.6.5](https://github.com/containous/traefik/tree/v1.6.5) (2018-07-09)
[All Commits](https://github.com/containous/traefik/compare/v1.6.4...v1.6.5)
**Bug fixes:**
- **[acme]** Add a mutex on local store for HTTPChallenges ([#3579](https://github.com/containous/traefik/pull/3579) by [Juliens](https://github.com/Juliens))
- **[consulcatalog]** Split the error handling from Consul Catalog (deadlock) ([#3560](https://github.com/containous/traefik/pull/3560) by [ortz](https://github.com/ortz))
- **[docker]** segment labels: multiple frontends for one backend. ([#3511](https://github.com/containous/traefik/pull/3511) by [ldez](https://github.com/ldez))
- **[kv]** Better support on same prefix at the same level in the KV ([#3532](https://github.com/containous/traefik/pull/3532) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[logs]** Add logs when error is generated in error handler ([#3567](https://github.com/containous/traefik/pull/3567) by [Juliens](https://github.com/Juliens))
- **[middleware]** Create middleware to be able to handle HTTP pipelining correctly ([#3513](https://github.com/containous/traefik/pull/3513) by [mmatur](https://github.com/mmatur))
**Documentation:**
- **[acme]** The gandiv5 provider works with wildcard ([#3506](https://github.com/containous/traefik/pull/3506) by [manu5801](https://github.com/manu5801))
- **[kv]** Update keyFile first/last line comment in kv-config.md ([#3558](https://github.com/containous/traefik/pull/3558) by [madnight](https://github.com/madnight))
- Minor formatting issue in user-guide ([#3546](https://github.com/containous/traefik/pull/3546) by [Vanuan](https://github.com/Vanuan))
## [v1.7.0-rc1](https://github.com/containous/traefik/tree/v1.7.0-rc1) (2018-07-09)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc1...v1.7.0-rc1)
**Enhancements:**
- **[acme]** Simplify get acme client ([#3499](https://github.com/containous/traefik/pull/3499) by [ldez](https://github.com/ldez))
- **[acme]** Simplify acme e2e tests. ([#3534](https://github.com/containous/traefik/pull/3534) by [ldez](https://github.com/ldez))
- **[acme]** Add option to select algorithm to generate ACME certificates ([#3319](https://github.com/containous/traefik/pull/3319) by [mmatur](https://github.com/mmatur))
- **[acme]** Enable to override certificates in key-value store when using storeconfig ([#3202](https://github.com/containous/traefik/pull/3202) by [thomasjpfan](https://github.com/thomasjpfan))
- **[acme]** ACME TLS ALPN ([#3553](https://github.com/containous/traefik/pull/3553) by [ldez](https://github.com/ldez))
- **[acme]** Remove acme provider dependency in server ([#3225](https://github.com/containous/traefik/pull/3225) by [Juliens](https://github.com/Juliens))
- **[api,cluster]** Improved cluster api to include the current leader node ([#3100](https://github.com/containous/traefik/pull/3100) by [aantono](https://github.com/aantono))
- **[authentication,k8s]** Auth support in frontends for k8s and file ([#3460](https://github.com/containous/traefik/pull/3460) by [Zatte](https://github.com/Zatte))
- **[authentication,middleware]** Add xforwarded method ([#3424](https://github.com/containous/traefik/pull/3424) by [erik-sjoestedt](https://github.com/erik-sjoestedt))
- **[authentication,middleware]** Forward auth headers ([#3521](https://github.com/containous/traefik/pull/3521) by [hwhelan-CB](https://github.com/hwhelan-CB))
- **[consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Auth support in frontends ([#3559](https://github.com/containous/traefik/pull/3559) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[consulcatalog,docker,ecs,file,k8s,kv,marathon,mesos,rancher]** Add SSLForceHost support. ([#3246](https://github.com/containous/traefik/pull/3246) by [ldez](https://github.com/ldez))
- **[consulcatalog]** Add support for stale reads from Consul catalog ([#3523](https://github.com/containous/traefik/pull/3523) by [marenzo](https://github.com/marenzo))
- **[docker]** Add a default value for the docker.network configuration ([#3471](https://github.com/containous/traefik/pull/3471) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[ecs]** Support for AWS ECS Fargate ([#3379](https://github.com/containous/traefik/pull/3379) by [mmatur](https://github.com/mmatur))
- **[ecs]** Add support for ECS constraints ([#3537](https://github.com/containous/traefik/pull/3537) by [andrewstucki](https://github.com/andrewstucki))
- **[ecs]** Support `traefik.backend` for ECS ([#3510](https://github.com/containous/traefik/pull/3510) by [hwhelan-CB](https://github.com/hwhelan-CB))
- **[ecs]** Allow binding ECS container port ([#3533](https://github.com/containous/traefik/pull/3533) by [andrewstucki](https://github.com/andrewstucki))
- **[healthcheck,consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Override health check scheme ([#3315](https://github.com/containous/traefik/pull/3315) by [ldez](https://github.com/ldez))
- **[healthcheck]** Support 3xx HTTP status codes for health check ([#3364](https://github.com/containous/traefik/pull/3364) by [SniperCZE](https://github.com/SniperCZE))
- **[healthcheck]** Support all 2xx HTTP status code for health check. ([#3362](https://github.com/containous/traefik/pull/3362) by [ldez](https://github.com/ldez))
- **[healthcheck]** Add HTTP headers to healthcheck. ([#3047](https://github.com/containous/traefik/pull/3047) by [zetaab](https://github.com/zetaab))
- **[k8s]** Add more k8s tests ([#3491](https://github.com/containous/traefik/pull/3491) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Substitude hardcoded &#34;&lt;namespace&gt;/&lt;name&gt;&#34; with k8s ListerGetter ([#3470](https://github.com/containous/traefik/pull/3470) by [yue9944882](https://github.com/yue9944882))
- **[k8s]** Custom frontend name for test helper ([#3444](https://github.com/containous/traefik/pull/3444) by [ldez](https://github.com/ldez))
- **[k8s]** Add annotation to allow modifiers to be used properly in kubernetes ([#3481](https://github.com/containous/traefik/pull/3481) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Create Global Backend Ingress ([#3404](https://github.com/containous/traefik/pull/3404) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Specify backend servers&#39; weight via annotation for kubernetes ([#3112](https://github.com/containous/traefik/pull/3112) by [yue9944882](https://github.com/yue9944882))
- **[k8s]** Support multi-port services. ([#3121](https://github.com/containous/traefik/pull/3121) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Mapping ExternalNames to custom ports ([#3231](https://github.com/containous/traefik/pull/3231) by [gildas](https://github.com/gildas))
- **[k8s]** Allow any kubernetes ingressClass value ([#3516](https://github.com/containous/traefik/pull/3516) by [rtreffer](https://github.com/rtreffer))
- **[k8s]** Enable Ingress Status updates ([#3324](https://github.com/containous/traefik/pull/3324) by [dtomcej](https://github.com/dtomcej))
- **[kv]** Use index-based syntax in KV tests. ([#3352](https://github.com/containous/traefik/pull/3352) by [ldez](https://github.com/ldez))
- **[logs,middleware]** Make accesslogs.logTheRoundTrip async to get lost performance ([#3152](https://github.com/containous/traefik/pull/3152) by [ryarnyah](https://github.com/ryarnyah))
- **[logs,middleware]** Added duration filter for logs ([#3463](https://github.com/containous/traefik/pull/3463) by [rodrigodiez](https://github.com/rodrigodiez))
- **[marathon]** Adding compatibility for marathon 1.5 ([#3505](https://github.com/containous/traefik/pull/3505) by [TrevinTeacutter](https://github.com/TrevinTeacutter))
- **[marathon]** Sane default and configurable Marathon request timeouts ([#3286](https://github.com/containous/traefik/pull/3286) by [marco-jantke](https://github.com/marco-jantke))
- **[mesos]** Segments Labels: Mesos ([#3383](https://github.com/containous/traefik/pull/3383) by [drewkerrigan](https://github.com/drewkerrigan))
- **[metrics]** Metrics: Add support for InfluxDB Database / RetentionPolicy and HTTP client ([#3391](https://github.com/containous/traefik/pull/3391) by [drewkerrigan](https://github.com/drewkerrigan))
- **[middleware,server]** Extreme Makeover: server refactoring ([#3461](https://github.com/containous/traefik/pull/3461) by [ldez](https://github.com/ldez))
- **[middleware,tracing]** Added integration support for DataDog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono))
- **[middleware,tracing]** Create a custom logger for jaeger ([#3541](https://github.com/containous/traefik/pull/3541) by [mmatur](https://github.com/mmatur))
- **[middleware]** Performance enhancements for the rules matchers. ([#3563](https://github.com/containous/traefik/pull/3563) by [ShaneSaww](https://github.com/ShaneSaww))
- **[middleware]** Extract internal router creation from server ([#3204](https://github.com/containous/traefik/pull/3204) by [Juliens](https://github.com/Juliens))
- **[rules]** CNAME flattening ([#3403](https://github.com/containous/traefik/pull/3403) by [gamalan](https://github.com/gamalan))
- **[servicefabric]** Add white list for Service Fabric ([#3079](https://github.com/containous/traefik/pull/3079) by [ldez](https://github.com/ldez))
- **[servicefabric]** Add HTTP headers to healthcheck. ([#3205](https://github.com/containous/traefik/pull/3205) by [ldez](https://github.com/ldez))
- **[tls]** Improve TLS Handshake ([#3512](https://github.com/containous/traefik/pull/3512) by [dtomcej](https://github.com/dtomcej))
- **[tls]** Support TLS MinVersion and CipherSuite as CLI option. ([#3107](https://github.com/containous/traefik/pull/3107) by [ldez](https://github.com/ldez))
- **[webui]** Add some missing elements in the WebUI ([#3327](https://github.com/containous/traefik/pull/3327) by [ldez](https://github.com/ldez))
- Minor changes ([#3554](https://github.com/containous/traefik/pull/3554) by [ldez](https://github.com/ldez))
- h2c server ([#3387](https://github.com/containous/traefik/pull/3387) by [Juliens](https://github.com/Juliens))
- Fix backend reuse ([#3312](https://github.com/containous/traefik/pull/3312) by [arnested](https://github.com/arnested))
- Call functions to enable block/mutex pprof profiles. ([#3564](https://github.com/containous/traefik/pull/3564) by [timoreimann](https://github.com/timoreimann))
- Implement h2c with backend ([#3371](https://github.com/containous/traefik/pull/3371) by [Juliens](https://github.com/Juliens))
- Upgrade GRPC dependencies ([#3342](https://github.com/containous/traefik/pull/3342) by [gottwald](https://github.com/gottwald))
- Generated assets file are only mandatory in main ([#3386](https://github.com/containous/traefik/pull/3386) by [Juliens](https://github.com/Juliens))
**Bug fixes:**
- **[acme]** Does not generate ACME certificate if domain is checked by dynamic certificate ([#3238](https://github.com/containous/traefik/pull/3238) by [Juliens](https://github.com/Juliens))
- **[k8s]** Fix panic setting ingress status ([#3492](https://github.com/containous/traefik/pull/3492) by [dtomcej](https://github.com/dtomcej))
- **[logs]** Add logs when error is generated in error handler ([#3571](https://github.com/containous/traefik/pull/3571) by [Juliens](https://github.com/Juliens))
- **[middleware]** Avoid retries when any data was written to the backend ([#3285](https://github.com/containous/traefik/pull/3285) by [marco-jantke](https://github.com/marco-jantke))
**Documentation:**
- **[k8s]** Add a k8s guide section on traffic splitting via service weights. ([#3556](https://github.com/containous/traefik/pull/3556) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Change code block of traefik-web-ui to match file ([#3542](https://github.com/containous/traefik/pull/3542) by [drewgwallace](https://github.com/drewgwallace))
- **[k8s]** Fix typo which breaks k8s example manifest ([#3441](https://github.com/containous/traefik/pull/3441) by [GeertJohan](https://github.com/GeertJohan))
- **[metrics]** Adding grafana dashboards based on prometheus metrics ([#3393](https://github.com/containous/traefik/pull/3393) by [deimosfr](https://github.com/deimosfr))
- **[servicefabric]** Fix Service Fabric docs to use v1.6 labels ([#3209](https://github.com/containous/traefik/pull/3209) by [jjcollinge](https://github.com/jjcollinge))
**Misc:**
- Merge v1.6.4 into master ([#3502](https://github.com/containous/traefik/pull/3502) by [ldez](https://github.com/ldez))
- Merge v1.6.3 into master ([#3439](https://github.com/containous/traefik/pull/3439) by [ldez](https://github.com/ldez))
- Merge v1.6.2 into master ([#3367](https://github.com/containous/traefik/pull/3367) by [ldez](https://github.com/ldez))
- Merge v1.6.1 into master ([#3326](https://github.com/containous/traefik/pull/3326) by [ldez](https://github.com/ldez))
- Merge v1.6.0 into master ([#3253](https://github.com/containous/traefik/pull/3253) by [ldez](https://github.com/ldez))
- Merge v1.6.0-rc6 into master ([#3203](https://github.com/containous/traefik/pull/3203) by [ldez](https://github.com/ldez))
- Merge v1.6.0-rc5 into master ([#3180](https://github.com/containous/traefik/pull/3180) by [ldez](https://github.com/ldez))
- Merge v1.6.0-rc4 into master ([#3129](https://github.com/containous/traefik/pull/3129) by [ldez](https://github.com/ldez))
## [v1.6.4](https://github.com/containous/traefik/tree/v1.6.4) (2018-06-15)
[All Commits](https://github.com/containous/traefik/compare/v1.6.3...v1.6.4)
**Bug fixes:**
- **[acme]** Use logrus writer instead of os.Stderr ([#3498](https://github.com/containous/traefik/pull/3498) by [ldez](https://github.com/ldez))
- **[consulcatalog]** Enclose IPv6 addresses in &#34;[]&#34; ([#3477](https://github.com/containous/traefik/pull/3477) by [herver](https://github.com/herver))
- **[docker,ecs,marathon,mesos,rancher]** Use net.JoinHostPort for servers URL ([#3484](https://github.com/containous/traefik/pull/3484) by [ldez](https://github.com/ldez))
- **[docker]** Backend name with docker-compose and segments. ([#3485](https://github.com/containous/traefik/pull/3485) by [ldez](https://github.com/ldez))
- **[oxy]** Handle buffer pool for oxy ([#3450](https://github.com/containous/traefik/pull/3450) by [Juliens](https://github.com/Juliens))
**Documentation:**
- **[acme]** The exoscale provider works with wildcard ([#3479](https://github.com/containous/traefik/pull/3479) by [greut](https://github.com/greut))
- **[consul,docker]** Edit wording ([#3438](https://github.com/containous/traefik/pull/3438) by [mayank23](https://github.com/mayank23))
- **[k8s]** Add missing annotation documentation. ([#3454](https://github.com/containous/traefik/pull/3454) by [ldez](https://github.com/ldez))
- **[kv]** Fix typo in kv user guide ([#3474](https://github.com/containous/traefik/pull/3474) by [shambarick](https://github.com/shambarick))
- Clean metrics documentation. ([#3488](https://github.com/containous/traefik/pull/3488) by [ldez](https://github.com/ldez))
## [v1.6.3](https://github.com/containous/traefik/tree/v1.6.3) (2018-06-05)
[All Commits](https://github.com/containous/traefik/compare/v1.6.2...v1.6.3)
**Enhancements:**
- **[acme]** Add user agent for ACME ([#3431](https://github.com/containous/traefik/pull/3431) by [ldez](https://github.com/ldez))
- **[acme]** Use to the stable version of Lego ([#3418](https://github.com/containous/traefik/pull/3418) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[acme,cluster]** Improve ACME account registration URI management ([#3398](https://github.com/containous/traefik/pull/3398) by [nmengin](https://github.com/nmengin))
- **[acme,cluster]** Remove ACME empty certificates from KV store ([#3389](https://github.com/containous/traefik/pull/3389) by [nmengin](https://github.com/nmengin))
- **[consulcatalog]** Reflect changes in catalog healthy nodes in healthCheck watch ([#3390](https://github.com/containous/traefik/pull/3390) by [thebinary](https://github.com/thebinary))
- **[consulcatalog]** Detect change when service or node are in maintenance mode ([#3434](https://github.com/containous/traefik/pull/3434) by [mmatur](https://github.com/mmatur))
- **[k8s]** Update Kubernetes provider to support IPv6 Backends ([#3432](https://github.com/containous/traefik/pull/3432) by [dtomcej](https://github.com/dtomcej))
- **[logs,middleware]** Add URL and Host for some access logs. ([#3430](https://github.com/containous/traefik/pull/3430) by [ldez](https://github.com/ldez))
- **[metrics]** Improve Prometheus metrics removal ([#3287](https://github.com/containous/traefik/pull/3287) by [marco-jantke](https://github.com/marco-jantke))
- **[middleware]** Whitelist and XFF. ([#3411](https://github.com/containous/traefik/pull/3411) by [ldez](https://github.com/ldez))
- **[middleware]** Error pages and header merge ([#3394](https://github.com/containous/traefik/pull/3394) by [ldez](https://github.com/ldez))
- **[websocket]** Includes the headers in the HTTP response of a websocket request ([#3425](https://github.com/containous/traefik/pull/3425) by [geraldcroes](https://github.com/geraldcroes))
- **[webui]** Webui Whitelist overflow. ([#3412](https://github.com/containous/traefik/pull/3412) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme]** Docs: ACME Overhaul ([#3421](https://github.com/containous/traefik/pull/3421) by [Dargmuesli](https://github.com/Dargmuesli))
- **[acme]** Minor documentation changes ([#3405](https://github.com/containous/traefik/pull/3405) by [amincheloh](https://github.com/amincheloh))
- **[k8s]** Helm installation using values ([#3392](https://github.com/containous/traefik/pull/3392) by [erikaulin](https://github.com/erikaulin))
- **[k8s]** Update Kubernetes Port Documentation ([#3368](https://github.com/containous/traefik/pull/3368) by [dtomcej](https://github.com/dtomcej))
## [v1.6.2](https://github.com/containous/traefik/tree/v1.6.2) (2018-05-22)
[All Commits](https://github.com/containous/traefik/compare/v1.6.1...v1.6.2)
**Bug fixes:**
- **[acme]** fix: acme errors management. ([#3329](https://github.com/containous/traefik/pull/3329) by [ldez](https://github.com/ldez))
- **[acme]** Force to use ACME v02 endpoint. ([#3358](https://github.com/containous/traefik/pull/3358) by [ldez](https://github.com/ldez))
- **[file]** No template parsing on traefik configuration file ([#3347](https://github.com/containous/traefik/pull/3347) by [Juliens](https://github.com/Juliens))
- **[k8s]** Add redirect-permanent to kubernetes template ([#3332](https://github.com/containous/traefik/pull/3332) by [dtomcej](https://github.com/dtomcej))
- **[logs]** Enhance Load-balancing method validation log. ([#3361](https://github.com/containous/traefik/pull/3361) by [ldez](https://github.com/ldez))
- **[middleware]** Fix error pages content. ([#3337](https://github.com/containous/traefik/pull/3337) by [ldez](https://github.com/ldez))
- **[webui]** Route rules overlaps in UI ([#3333](https://github.com/containous/traefik/pull/3333) by [ldez](https://github.com/ldez))
- **[webui]** WebUI typo into the buffering section. ([#3363](https://github.com/containous/traefik/pull/3363) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme]** Update caServer to letsencrypt one in examples ([#3339](https://github.com/containous/traefik/pull/3339) by [woernfl](https://github.com/woernfl))
- **[docker]** Add command for basic auth with Docker Compose ([#3346](https://github.com/containous/traefik/pull/3346) by [DeamonMV](https://github.com/DeamonMV))
- **[docker]** Removes ambiguity with the word &#39;default&#39; ([#3344](https://github.com/containous/traefik/pull/3344) by [ldez](https://github.com/ldez))
- **[kv]** Add basicAuth example for KV ([#3274](https://github.com/containous/traefik/pull/3274) by [MichaelErmer](https://github.com/MichaelErmer))
- **[provider]** Update docs to reflect Provider wording ([#3331](https://github.com/containous/traefik/pull/3331) by [dtomcej](https://github.com/dtomcej))
- **[servicefabric]** Update docs to match SF provider labels ([#3335](https://github.com/containous/traefik/pull/3335) by [jjcollinge](https://github.com/jjcollinge))
## [v1.6.1](https://github.com/containous/traefik/tree/v1.6.1) (2018-05-14)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0...v1.6.1)
**Bug fixes:**
- **[acme]** Add missing deprecation info in CLI help. ([#3291](https://github.com/containous/traefik/pull/3291) by [ldez](https://github.com/ldez))
- **[docker,marathon,rancher]** Fix segment backend name ([#3317](https://github.com/containous/traefik/pull/3317) by [ldez](https://github.com/ldez))
- **[logs,middleware]** Error when accesslog and error pages ([#3314](https://github.com/containous/traefik/pull/3314) by [ldez](https://github.com/ldez))
- **[middleware,tracing]** Fix wrong tag in forward span in tracing middleware ([#3279](https://github.com/containous/traefik/pull/3279) by [mmatur](https://github.com/mmatur))
- **[webui]** Fix webui ([#3299](https://github.com/containous/traefik/pull/3299) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s]** Add Documentation update for Kubernetes Ingress ([#3294](https://github.com/containous/traefik/pull/3294) by [dtomcej](https://github.com/dtomcej))
- **[tls]** Enhance entry point TLS CLI reference. ([#3290](https://github.com/containous/traefik/pull/3290) by [ldez](https://github.com/ldez))
- Typo in documentation ([#3261](https://github.com/containous/traefik/pull/3261) by [blakethepatton](https://github.com/blakethepatton))
## [v1.6.0](https://github.com/containous/traefik/tree/v1.6.0) (2018-04-30)
[Commits](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.6.0)
[Commits pre RC](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.6.0-rc1)
**Enhancements:**
- **[acme]** Create ACME Provider ([#2889](https://github.com/containous/traefik/pull/2889) by [nmengin](https://github.com/nmengin))
- **[acme]** Update Lego (Gandi API v5, cloudxns, ...) ([#2844](https://github.com/containous/traefik/pull/2844) by [ldez](https://github.com/ldez))
- **[acme]** Simplify storing renewed acme certificate ([#2614](https://github.com/containous/traefik/pull/2614) by [ferhatelmas](https://github.com/ferhatelmas))
- **[acme]** ACME V2 Integration ([#3063](https://github.com/containous/traefik/pull/3063) by [nmengin](https://github.com/nmengin))
- **[acme]** Bump Lego Version for GoDaddy DNS Provider ([#2482](https://github.com/containous/traefik/pull/2482) by [sjawhar](https://github.com/sjawhar))
- **[acme]** Delete TLS-SNI-01 challenge from ACME ([#2971](https://github.com/containous/traefik/pull/2971) by [nmengin](https://github.com/nmengin))
- **[acme]** Create backup file during migration from ACME V1 to ACME V2 ([#3191](https://github.com/containous/traefik/pull/3191) by [nmengin](https://github.com/nmengin))
- **[acme]** Generate wildcard certificate with SANs in ACME ([#3167](https://github.com/containous/traefik/pull/3167) by [nmengin](https://github.com/nmengin))
- **[api,cluster]** Added cluster/leader endpoint ([#3009](https://github.com/containous/traefik/pull/3009) by [aantono](https://github.com/aantono))
- **[authentication]** Forward Authentication: add X-Forwarded-Uri ([#2398](https://github.com/containous/traefik/pull/2398) by [sebastianbauer](https://github.com/sebastianbauer))
- **[boltdb,consul,etcd,kv,zk]** Add all available configuration to KV Backend ([#2652](https://github.com/containous/traefik/pull/2652) by [ldez](https://github.com/ldez))
- **[boltdb,consul,etcd,kv,zk]** homogenization of templates: KV ([#2661](https://github.com/containous/traefik/pull/2661) by [ldez](https://github.com/ldez))
- **[boltdb,consul,etcd,kv,zk]** Homogenization of the providers (part 1): KV ([#2616](https://github.com/containous/traefik/pull/2616) by [ldez](https://github.com/ldez))
- **[consul,consulcatalog]** Homogenization of templates: Consul Catalog ([#2668](https://github.com/containous/traefik/pull/2668) by [ldez](https://github.com/ldez))
- **[consul,consulcatalog]** Split consul and consul catalog. ([#2655](https://github.com/containous/traefik/pull/2655) by [ldez](https://github.com/ldez))
- **[consulcatalog,ecs,mesos]** Factorize labels managements. ([#3099](https://github.com/containous/traefik/pull/3099) by [ldez](https://github.com/ldez))
- **[consulcatalog]** Check for endpoints while detecting Consul service changes ([#2882](https://github.com/containous/traefik/pull/2882) by [caseycs](https://github.com/caseycs))
- **[consulcatalog]** TLS Support for ConsulCatalog ([#2900](https://github.com/containous/traefik/pull/2900) by [mmatur](https://github.com/mmatur))
- **[consulcatalog]** Add all available tags to Consul Catalog Backend ([#2646](https://github.com/containous/traefik/pull/2646) by [ldez](https://github.com/ldez))
- **[docker,docker/swarm]** Fix support for macvlan driver in docker provider ([#2827](https://github.com/containous/traefik/pull/2827) by [mmatur](https://github.com/mmatur))
- **[docker,marathon,rancher]** Segments Labels: Rancher &amp; Marathon ([#3073](https://github.com/containous/traefik/pull/3073) by [ldez](https://github.com/ldez))
- **[docker]** Add all available labels to Docker Backend ([#2584](https://github.com/containous/traefik/pull/2584) by [ldez](https://github.com/ldez))
- **[docker]** Homogenization of templates: Docker ([#2659](https://github.com/containous/traefik/pull/2659) by [ldez](https://github.com/ldez))
- **[docker]** Custom headers by service labels for docker backends ([#2514](https://github.com/containous/traefik/pull/2514) by [Tiscs](https://github.com/Tiscs))
- **[docker]** Segment labels: Docker ([#3055](https://github.com/containous/traefik/pull/3055) by [ldez](https://github.com/ldez))
- **[dynamodb,ecs]** Upgrade AWS SKD to version v1.13.1 ([#2908](https://github.com/containous/traefik/pull/2908) by [mmatur](https://github.com/mmatur))
- **[ecs]** Add all available labels to ECS Backend ([#2605](https://github.com/containous/traefik/pull/2605) by [ldez](https://github.com/ldez))
- **[ecs]** Homogenization of templates: ECS ([#2663](https://github.com/containous/traefik/pull/2663) by [ldez](https://github.com/ldez))
- **[ecs]** Factorize labels managements. ([#3159](https://github.com/containous/traefik/pull/3159) by [ldez](https://github.com/ldez))
- **[eureka]** Homogenization of templates: Eureka ([#2846](https://github.com/containous/traefik/pull/2846) by [ldez](https://github.com/ldez))
- **[eureka]** Replace Delay by RefreshSecond in Eureka ([#2972](https://github.com/containous/traefik/pull/2972) by [ldez](https://github.com/ldez))
- **[file]** Added support for templates to file provider ([#2991](https://github.com/containous/traefik/pull/2991) by [aantono](https://github.com/aantono))
- **[healthcheck]** Toggle /ping to artificially return unhealthy response on SIGTERM during requestAcceptGraceTimeout interval ([#3062](https://github.com/containous/traefik/pull/3062) by [ravilr](https://github.com/ravilr))
- **[healthcheck]** Improve logging output for failing healthchecks ([#2443](https://github.com/containous/traefik/pull/2443) by [marco-jantke](https://github.com/marco-jantke))
- **[k8s,tls]** Add support for fetching k8s Ingress TLS data from secrets ([#2439](https://github.com/containous/traefik/pull/2439) by [gopenguin](https://github.com/gopenguin))
- **[k8s]** Introduce k8s informer factory ([#2867](https://github.com/containous/traefik/pull/2867) by [yue9944882](https://github.com/yue9944882))
- **[k8s]** Add all available annotations to k8s Backend ([#2612](https://github.com/containous/traefik/pull/2612) by [ldez](https://github.com/ldez))
- **[k8s]** Bump kubernetes/client-go ([#2848](https://github.com/containous/traefik/pull/2848) by [yue9944882](https://github.com/yue9944882))
- **[k8s]** Add app-root annotation support for kubernetes ingress ([#2522](https://github.com/containous/traefik/pull/2522) by [yue9944882](https://github.com/yue9944882))
- **[k8s]** Builders in k8s tests ([#2513](https://github.com/containous/traefik/pull/2513) by [ldez](https://github.com/ldez))
- **[k8s]** Allow custom value for kubernetes.io/ingress.class annotation ([#2222](https://github.com/containous/traefik/pull/2222) by [yuvipanda](https://github.com/yuvipanda))
- **[logs,middleware]** Add access log filter for retry attempts ([#3042](https://github.com/containous/traefik/pull/3042) by [marco-jantke](https://github.com/marco-jantke))
- **[logs,middleware]** Add username in accesslog ([#2111](https://github.com/containous/traefik/pull/2111) by [bastiaanb](https://github.com/bastiaanb))
- **[logs,middleware]** Ultimate Access log filter ([#2988](https://github.com/containous/traefik/pull/2988) by [mmatur](https://github.com/mmatur))
- **[logs]** Allow overriding the log level in debug mode. ([#3050](https://github.com/containous/traefik/pull/3050) by [timoreimann](https://github.com/timoreimann))
- **[logs]** Display file log when test fails. ([#2801](https://github.com/containous/traefik/pull/2801) by [ldez](https://github.com/ldez))
- **[marathon]** Remove health check filter from Marathon tasks. ([#2817](https://github.com/containous/traefik/pull/2817) by [timoreimann](https://github.com/timoreimann))
- **[marathon]** Add all available labels to Marathon Backend ([#2602](https://github.com/containous/traefik/pull/2602) by [ldez](https://github.com/ldez))
- **[marathon]** homogenization of templates: Marathon ([#2665](https://github.com/containous/traefik/pull/2665) by [ldez](https://github.com/ldez))
- **[mesos]** Add all available labels to Mesos Backend ([#2687](https://github.com/containous/traefik/pull/2687) by [ldez](https://github.com/ldez))
- **[metrics]** Added entrypoint metrics to influxdb ([#2992](https://github.com/containous/traefik/pull/2992) by [adityacs](https://github.com/adityacs))
- **[metrics]** Remove unnecessary conversion ([#2850](https://github.com/containous/traefik/pull/2850) by [ferhatelmas](https://github.com/ferhatelmas))
- **[metrics]** Extend metrics and rebuild prometheus exporting logic ([#2567](https://github.com/containous/traefik/pull/2567) by [marco-jantke](https://github.com/marco-jantke))
- **[metrics]** Added missing metrics to registry for DataDog and StatsD ([#2890](https://github.com/containous/traefik/pull/2890) by [aantono](https://github.com/aantono))
- **[middleware,consul,consulcatalog,docker,ecs,k8s,marathon,mesos,rancher]** New option in secure middleware ([#2958](https://github.com/containous/traefik/pull/2958) by [mmatur](https://github.com/mmatur))
- **[middleware,consulcatalog,docker,ecs,k8s,kv,marathon,mesos,rancher]** Ability to use &#34;X-Forwarded-For&#34; as a source of IP for white list. ([#3070](https://github.com/containous/traefik/pull/3070) by [ldez](https://github.com/ldez))
- **[middleware,docker]** Use pointer of error pages ([#2607](https://github.com/containous/traefik/pull/2607) by [ldez](https://github.com/ldez))
- **[middleware,provider]** Redirection: permanent move option. ([#2774](https://github.com/containous/traefik/pull/2774) by [ldez](https://github.com/ldez))
- **[middleware]** Add tests on IPWhiteLister. ([#3106](https://github.com/containous/traefik/pull/3106) by [ldez](https://github.com/ldez))
- **[middleware]** Change port of traefik for error pages integration test ([#2907](https://github.com/containous/traefik/pull/2907) by [mmatur](https://github.com/mmatur))
- **[middleware]** Remove unnecessary returns in tracing setup ([#2880](https://github.com/containous/traefik/pull/2880) by [ferhatelmas](https://github.com/ferhatelmas))
- **[middleware]** Request buffering middleware ([#2217](https://github.com/containous/traefik/pull/2217) by [harnash](https://github.com/harnash))
- **[middleware]** Add new options to the CLI entrypoint definition. ([#2799](https://github.com/containous/traefik/pull/2799) by [ldez](https://github.com/ldez))
- **[provider]** No error pages must return nil. ([#2610](https://github.com/containous/traefik/pull/2610) by [ldez](https://github.com/ldez))
- **[provider]** Homogenization of the providers (part 1) ([#2518](https://github.com/containous/traefik/pull/2518) by [ldez](https://github.com/ldez))
- **[rancher]** Add all available labels to Rancher Backend ([#2601](https://github.com/containous/traefik/pull/2601) by [ldez](https://github.com/ldez))
- **[rancher]** Homogenization of templates: Rancher ([#2662](https://github.com/containous/traefik/pull/2662) by [ldez](https://github.com/ldez))
- **[rules]** Externalize Træfik rules in a dedicated package ([#2933](https://github.com/containous/traefik/pull/2933) by [nmengin](https://github.com/nmengin))
- **[servicefabric]** Use shared label system ([#3197](https://github.com/containous/traefik/pull/3197) by [ldez](https://github.com/ldez))
- **[servicefabric]** Update Service Fabric backend. ([#3064](https://github.com/containous/traefik/pull/3064) by [ldez](https://github.com/ldez))
- **[servicefabric]** Add white list for Service Fabric ([#3079](https://github.com/containous/traefik/pull/3079) by [ldez](https://github.com/ldez))
- **[tls]** Use default entryPoints when certificates are added with no entryPoints. ([#2534](https://github.com/containous/traefik/pull/2534) by [nmengin](https://github.com/nmengin))
- **[tracing]** Handle zipkin collector creation ([#2860](https://github.com/containous/traefik/pull/2860) by [ferhatelmas](https://github.com/ferhatelmas))
- **[tracing]** Opentracing support ([#2587](https://github.com/containous/traefik/pull/2587) by [tcolgate](https://github.com/tcolgate) and [mmatur](https://github.com/mmatur))
- **[webui]** New web ui ([#2226](https://github.com/containous/traefik/pull/2226) by [jkuri](https://github.com/jkuri))
- **[webui]** Add status code text to webui bar chart tooltip ([#2639](https://github.com/containous/traefik/pull/2639) by [wader](https://github.com/wader))
- Logger and Leaks ([#2847](https://github.com/containous/traefik/pull/2847) by [ldez](https://github.com/ldez))
- Separate command from the main package ([#2951](https://github.com/containous/traefik/pull/2951) by [Juliens](https://github.com/Juliens))
- Use context in Server ([#3007](https://github.com/containous/traefik/pull/3007) by [Juliens](https://github.com/Juliens))
**Bug fixes:**
- **[acme]** Check all the C/N and SANs of provided certificates before generating ACME certificates in ACME provider ([#2970](https://github.com/containous/traefik/pull/2970) by [nmengin](https://github.com/nmengin))
- **[acme]** Update lego. ([#3158](https://github.com/containous/traefik/pull/3158) by [ldez](https://github.com/ldez))
- **[acme]** Fix panic with wrong ACME configuration ([#3084](https://github.com/containous/traefik/pull/3084) by [nmengin](https://github.com/nmengin))
- **[acme]** Minor updates to dumpcerts.sh ([#3116](https://github.com/containous/traefik/pull/3116) by [mathuin](https://github.com/mathuin))
- **[acme]** Add ACME certificates only on ACME EntryPoint ([#3136](https://github.com/containous/traefik/pull/3136) by [nmengin](https://github.com/nmengin))
- **[acme]** Add TTL and custom Timeout in DigitalOcean DNS provider ([#3143](https://github.com/containous/traefik/pull/3143) by [ldez](https://github.com/ldez))
- **[acme]** Fix acme.json file automatic creation ([#3156](https://github.com/containous/traefik/pull/3156) by [nmengin](https://github.com/nmengin))
- **[acme]** Fix wildcard match to ACME domains in cluster mode ([#3080](https://github.com/containous/traefik/pull/3080) by [oldmantaiter](https://github.com/oldmantaiter))
- **[api,cluster]** Moved /api/cluster/leadership handler under public routes (requires no authentication) ([#3101](https://github.com/containous/traefik/pull/3101) by [aantono](https://github.com/aantono))
- **[authentication,middleware]** Forward auth: copy response headers when auth failed. ([#3207](https://github.com/containous/traefik/pull/3207) by [ldez](https://github.com/ldez))
- **[consul,docker,ecs,eureka,k8s,kv,marathon,mesos,rancher]** Server weight zero ([#3130](https://github.com/containous/traefik/pull/3130) by [ldez](https://github.com/ldez))
- **[docker,k8s,marathon]** Fix custom headers template ([#2622](https://github.com/containous/traefik/pull/2622) by [ldez](https://github.com/ldez))
- **[docker,marathon,mesos,rancher]** Fix: label &#39;traefik.domain&#39; ([#3201](https://github.com/containous/traefik/pull/3201) by [ldez](https://github.com/ldez))
- **[docker,rancher]** Frontend rule and segment labels. ([#3091](https://github.com/containous/traefik/pull/3091) by [ldez](https://github.com/ldez))
- **[docker,rancher]** Ignore server for container with empty IP address. ([#3213](https://github.com/containous/traefik/pull/3213) by [ldez](https://github.com/ldez))
- **[docker]** Fix multiple frontends with docker-compose --scale ([#3190](https://github.com/containous/traefik/pull/3190) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[healthcheck]** Remove unnecessary mutex usage in health checks ([#2726](https://github.com/containous/traefik/pull/2726) by [marco-jantke](https://github.com/marco-jantke))
- **[k8s]** Missing annotation prefix support. ([#2915](https://github.com/containous/traefik/pull/2915) by [ldez](https://github.com/ldez))
- **[k8s]** Remove hardcoded frontend prefix in Kubernetes template ([#2914](https://github.com/containous/traefik/pull/2914) by [psalaberria002](https://github.com/psalaberria002))
- **[k8s]** Limit label selector to Ingress factory. ([#3137](https://github.com/containous/traefik/pull/3137) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Fixes prefixed annotations support. ([#3110](https://github.com/containous/traefik/pull/3110) by [ldez](https://github.com/ldez))
- **[logs,middleware]** Fix bad access log ([#2682](https://github.com/containous/traefik/pull/2682) by [mmatur](https://github.com/mmatur))
- **[logs]** Add missing argument in log. ([#3188](https://github.com/containous/traefik/pull/3188) by [chemidy](https://github.com/chemidy))
- **[marathon]** Several apps with same backend name in Marathon. ([#3109](https://github.com/containous/traefik/pull/3109) by [ldez](https://github.com/ldez))
- **[mesos]** fix: overflow on 32 bits arch. ([#3127](https://github.com/containous/traefik/pull/3127) by [ldez](https://github.com/ldez))
- **[metrics]** Fix duplicated tags in InfluxDB ([#3189](https://github.com/containous/traefik/pull/3189) by [mmatur](https://github.com/mmatur))
- **[middleware,consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Fix: error pages ([#3138](https://github.com/containous/traefik/pull/3138) by [ldez](https://github.com/ldez))
- **[middleware,tracing]** Fix &lt;nil&gt; tracer value in KV ([#2911](https://github.com/containous/traefik/pull/2911) by [mmatur](https://github.com/mmatur))
- **[middleware,tracing]** Fix nil value when tracing is enabled ([#3192](https://github.com/containous/traefik/pull/3192) by [mmatur](https://github.com/mmatur))
- **[middleware]** Use responseModifier to override secure headers ([#2946](https://github.com/containous/traefik/pull/2946) by [mmatur](https://github.com/mmatur))
- **[middleware]** Correct conditional setting of buffering retry expression. ([#2865](https://github.com/containous/traefik/pull/2865) by [ldez](https://github.com/ldez))
- **[middleware]** Fix high memory usage in retry middleware ([#2740](https://github.com/containous/traefik/pull/2740) by [marco-jantke](https://github.com/marco-jantke))
- **[middleware]** Fix whitelist and XFF. ([#3211](https://github.com/containous/traefik/pull/3211) by [ldez](https://github.com/ldez))
- **[middleware]** Fix panic in atomic on ARM and x86-32 platforms ([#3195](https://github.com/containous/traefik/pull/3195) by [mmatur](https://github.com/mmatur))
- **[middleware]** Redirect to HTTPS first before basic auth if header redirect (secure) is set ([#3187](https://github.com/containous/traefik/pull/3187) by [SantoDE](https://github.com/SantoDE))
- **[middleware]** Fix error pages redirect and headers. ([#3217](https://github.com/containous/traefik/pull/3217) by [ldez](https://github.com/ldez))
- **[provider]** Add some missing quotes in templates ([#2973](https://github.com/containous/traefik/pull/2973) by [ldez](https://github.com/ldez))
- **[servicefabric]** Fix backend name for stateful service and more. ([#3183](https://github.com/containous/traefik/pull/3183) by [ldez](https://github.com/ldez))
- **[tracing]** Fix missing configuration for jaeger reporter ([#2720](https://github.com/containous/traefik/pull/2720) by [mmatur](https://github.com/mmatur))
- **[tracing]** Tracing statusCodeTracker need to implement CloseNotify ([#2733](https://github.com/containous/traefik/pull/2733) by [mmatur](https://github.com/mmatur))
- **[tracing]** Fix integration tests in tracing ([#2759](https://github.com/containous/traefik/pull/2759) by [mmatur](https://github.com/mmatur))
- **[webui]** Remove useless ACME tab from UI. ([#3154](https://github.com/containous/traefik/pull/3154) by [ldez](https://github.com/ldez))
- **[webui]** Add redirect section. ([#3243](https://github.com/containous/traefik/pull/3243) by [ldez](https://github.com/ldez))
**Documentation:**
- **[docker]** Add default values for some Docker labels ([#2604](https://github.com/containous/traefik/pull/2604) by [ldez](https://github.com/ldez))
- **[file]** Add documentation about Templating in backend file ([#3223](https://github.com/containous/traefik/pull/3223) by [nmengin](https://github.com/nmengin))
- **[k8s]** Update traefik-ds.yaml with --api command line parameter ([#2803](https://github.com/containous/traefik/pull/2803) by [maniankara](https://github.com/maniankara))
- **[k8s]** Remove web provider in example ([#2807](https://github.com/containous/traefik/pull/2807) by [pigletfly](https://github.com/pigletfly))
- **[k8s]** Drop capabilities in Kubernetes DaemonSet example ([#3028](https://github.com/containous/traefik/pull/3028) by [nogoegst](https://github.com/nogoegst))
- **[k8s]** Docs: Fix typos in k8s user-guide ([#2898](https://github.com/containous/traefik/pull/2898) by [cez81](https://github.com/cez81))
- **[k8s]** Change boolean annotation values to string ([#2839](https://github.com/containous/traefik/pull/2839) by [hobti01](https://github.com/hobti01))
- **[k8s]** Update kubernetes.md ([#3093](https://github.com/containous/traefik/pull/3093) by [rdrgporto](https://github.com/rdrgporto))
- **[k8s]** Document custom k8s ingress class usage in guide. ([#3242](https://github.com/containous/traefik/pull/3242) by [timoreimann](https://github.com/timoreimann))
- **[k8s]** Update kubernetes.md ([#3171](https://github.com/containous/traefik/pull/3171) by [andreyfedoseev](https://github.com/andreyfedoseev))
- **[provider]** Split security labels and custom labels documentation. ([#2872](https://github.com/containous/traefik/pull/2872) by [ldez](https://github.com/ldez))
- **[provider]** Remove non-supported label. ([#3065](https://github.com/containous/traefik/pull/3065) by [ldez](https://github.com/ldez))
- **[provider]** Remove obsolete paragraph about error pages. ([#2608](https://github.com/containous/traefik/pull/2608) by [ldez](https://github.com/ldez))
- **[provider]** Cleaning labels/annotations documentation. ([#3245](https://github.com/containous/traefik/pull/3245) by [ldez](https://github.com/ldez))
- **[provider]** Fix template version documentation. ([#3184](https://github.com/containous/traefik/pull/3184) by [ldez](https://github.com/ldez))
- **[servicefabric]** Add SF to supported backends in docs ([#3033](https://github.com/containous/traefik/pull/3033) by [lawrencegripper](https://github.com/lawrencegripper))
- **[servicefabric]** Update SF white list documentation section. ([#3082](https://github.com/containous/traefik/pull/3082) by [ldez](https://github.com/ldez))
- **[tracing]** Fix typo in doc for rate limit label ([#2790](https://github.com/containous/traefik/pull/2790) by [mmatur](https://github.com/mmatur))
- **[tracing]** Add Tracing entry in the documentation. ([#2713](https://github.com/containous/traefik/pull/2713) by [ldez](https://github.com/ldez))
- **[tracing]** Fix documentation for tracing with Jaeger ([#3227](https://github.com/containous/traefik/pull/3227) by [mmatur](https://github.com/mmatur))
- **[webui]** doc: update Traefik images. ([#3241](https://github.com/containous/traefik/pull/3241) by [ldez](https://github.com/ldez))
- Fix typo in documentation ([#3215](https://github.com/containous/traefik/pull/3215) by [arnaslu](https://github.com/arnaslu))
- Minor improvements to documentation ([#3221](https://github.com/containous/traefik/pull/3221) by [colincoller](https://github.com/colincoller))
- Update some examples ([#3150](https://github.com/containous/traefik/pull/3150) by [zaporylie](https://github.com/zaporylie))
- Normalize parameter names in configs ([#3132](https://github.com/containous/traefik/pull/3132) by [kachkaev](https://github.com/kachkaev))
- Fixed documentation urls on README.md ([#3102](https://github.com/containous/traefik/pull/3102) by [emir](https://github.com/emir))
- Fix typo and tweak formatting in quickstart ([#3250](https://github.com/containous/traefik/pull/3250) by [alexymik](https://github.com/alexymik))
- Fix basic documentation ([#3086](https://github.com/containous/traefik/pull/3086) by [mmatur](https://github.com/mmatur))
- Prepare release v1.6.0-rc6 ([#3199](https://github.com/containous/traefik/pull/3199) by [mmatur](https://github.com/mmatur))
- Prepare release v1.6.0-rc5 ([#3179](https://github.com/containous/traefik/pull/3179) by [Juliens](https://github.com/Juliens))
- Prepare release v1.6.0-rc4 ([#3126](https://github.com/containous/traefik/pull/3126) by [ldez](https://github.com/ldez))
- Prepare release v1.6.0-rc3 ([#3096](https://github.com/containous/traefik/pull/3096) by [ldez](https://github.com/ldez))
- Prepare release v1.6.0-rc2 ([#3087](https://github.com/containous/traefik/pull/3087) by [nmengin](https://github.com/nmengin))
- Prepare release v1.6.0-rc1 ([#3078](https://github.com/containous/traefik/pull/3078) by [Juliens](https://github.com/Juliens))
- Prepare release v1.6.0 ([#3251](https://github.com/containous/traefik/pull/3251) by [Juliens](https://github.com/Juliens))
**Misc:**
- **[oxy]** Disable closeNotify when method GET for http pipelining ([#3108](https://github.com/containous/traefik/pull/3108) by [Juliens](https://github.com/Juliens))
- **[boltdb,consul,etcd,kv,zk]** Migrate from libkv to valkeyrie library ([#2743](https://github.com/containous/traefik/pull/2743) by [nmengin](https://github.com/nmengin))
- Drop unnecessary type conversions ([#2583](https://github.com/containous/traefik/pull/2583) by [ferhatelmas](https://github.com/ferhatelmas))
- Code simplification ([#2516](https://github.com/containous/traefik/pull/2516) by [ferhatelmas](https://github.com/ferhatelmas))
- Merge v1.5.4 into master ([#3024](https://github.com/containous/traefik/pull/3024) by [ldez](https://github.com/ldez))
- Merge v1.5.3 into master ([#2943](https://github.com/containous/traefik/pull/2943) by [ldez](https://github.com/ldez))
- Merge v1.5.2 into master ([#2843](https://github.com/containous/traefik/pull/2843) by [ldez](https://github.com/ldez))
- Merge v1.5.1 into master ([#2781](https://github.com/containous/traefik/pull/2781) by [ldez](https://github.com/ldez))
- Merge v1.5.0-rc5 into master ([#2708](https://github.com/containous/traefik/pull/2708) by [ldez](https://github.com/ldez))
- Merge v1.5.0-rc3 into master ([#2600](https://github.com/containous/traefik/pull/2600) by [ldez](https://github.com/ldez))
- Merge v1.5.0-rc2 into master ([#2536](https://github.com/containous/traefik/pull/2536) by [ldez](https://github.com/ldez))
## [v1.6.0-rc6](https://github.com/containous/traefik/tree/v1.6.0-rc6) (2018-04-17)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc5...v1.6.0-rc6)
**Enhancements:**
- **[acme]** Create backup file during migration from ACME V1 to ACME V2 ([#3191](https://github.com/containous/traefik/pull/3191) by [nmengin](https://github.com/nmengin))
- **[servicefabric]** Use shared label system ([#3197](https://github.com/containous/traefik/pull/3197) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[docker]** Fix multiple frontends with docker-compose --scale ([#3190](https://github.com/containous/traefik/pull/3190) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[metrics]** Fix duplicated tags in InfluxDB ([#3189](https://github.com/containous/traefik/pull/3189) by [mmatur](https://github.com/mmatur))
- **[middleware,tracing]** Fix nil value when tracing is enabled ([#3192](https://github.com/containous/traefik/pull/3192) by [mmatur](https://github.com/mmatur))
- **[middleware]** Fix panic in atomic on ARM and x86-32 platforms ([#3195](https://github.com/containous/traefik/pull/3195) by [mmatur](https://github.com/mmatur))
- **[middleware]** Redirect to HTTPS first before basic auth if header redirect (secure) is set ([#3187](https://github.com/containous/traefik/pull/3187) by [SantoDE](https://github.com/SantoDE))
- **[servicefabric]** Fix backend name for stateful service and more. ([#3183](https://github.com/containous/traefik/pull/3183) by [ldez](https://github.com/ldez))
- Add missing argument in log. ([#3188](https://github.com/containous/traefik/pull/3188) by [chemidy](https://github.com/chemidy))
**Documentation:**
- **[provider]** Fix template version documentation. ([#3184](https://github.com/containous/traefik/pull/3184) by [ldez](https://github.com/ldez))
## [v1.6.0-rc5](https://github.com/containous/traefik/tree/v1.6.0-rc5) (2018-04-12)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc4...v1.6.0-rc5)
**Enhancements:**
- **[acme]** Generate wildcard certificate with SANs in ACME ([#3167](https://github.com/containous/traefik/pull/3167) by [nmengin](https://github.com/nmengin))
- **[ecs]** Factorize labels managements. ([#3159](https://github.com/containous/traefik/pull/3159) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[acme]** Update lego. ([#3158](https://github.com/containous/traefik/pull/3158) by [ldez](https://github.com/ldez))
- **[acme]** Fix acme.json file automatic creation ([#3156](https://github.com/containous/traefik/pull/3156) by [nmengin](https://github.com/nmengin))
- **[acme]** Minor updates to dumpcerts.sh ([#3116](https://github.com/containous/traefik/pull/3116) by [mathuin](https://github.com/mathuin))
- **[acme]** Add TTL and custom Timeout in DigitalOcean DNS provider ([#3143](https://github.com/containous/traefik/pull/3143) by [ldez](https://github.com/ldez))
- **[acme]** Add ACME certificates only on ACME EntryPoint ([#3136](https://github.com/containous/traefik/pull/3136) by [nmengin](https://github.com/nmengin))
- **[consul,docker,ecs,eureka,k8s,kv,marathon,mesos,rancher]** Server weight zero ([#3130](https://github.com/containous/traefik/pull/3130) by [ldez](https://github.com/ldez))
- **[k8s]** Limit label selector to Ingress factory. ([#3137](https://github.com/containous/traefik/pull/3137) by [timoreimann](https://github.com/timoreimann))
- **[middleware,consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Fix: error pages ([#3138](https://github.com/containous/traefik/pull/3138) by [ldez](https://github.com/ldez))
- **[webui]** Remove useless ACME tab from UI. ([#3154](https://github.com/containous/traefik/pull/3154) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s]** Update kubernetes.md ([#3171](https://github.com/containous/traefik/pull/3171) by [andreyfedoseev](https://github.com/andreyfedoseev))
- Update some examples ([#3150](https://github.com/containous/traefik/pull/3150) by [zaporylie](https://github.com/zaporylie))
- Normalize parameter names in configs ([#3132](https://github.com/containous/traefik/pull/3132) by [kachkaev](https://github.com/kachkaev))
**Misc:**
- **[oxy]** Disable closeNotify when method GET for http pipelining ([#3108](https://github.com/containous/traefik/pull/3108) by [Juliens](https://github.com/Juliens))
## [v1.6.0-rc4](https://github.com/containous/traefik/tree/v1.6.0-rc4) (2018-04-04)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc3...v1.6.0-rc4)
**Enhancements:**
- **[consulcatalog,ecs,mesos]** Factorize labels managements. ([#3099](https://github.com/containous/traefik/pull/3099) by [ldez](https://github.com/ldez))
- **[middleware]** Add tests on IPWhiteLister. ([#3106](https://github.com/containous/traefik/pull/3106) by [ldez](https://github.com/ldez))
**Bug fixes:**
- **[api,cluster]** Moved /api/cluster/leadership handler under public routes (requires no authentication) ([#3101](https://github.com/containous/traefik/pull/3101) by [aantono](https://github.com/aantono))
- **[k8s]** Fixes prefixed annotations support. ([#3110](https://github.com/containous/traefik/pull/3110) by [ldez](https://github.com/ldez))
- **[marathon]** Several apps with same backend name in Marathon. ([#3109](https://github.com/containous/traefik/pull/3109) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s]** Update kubernetes.md ([#3093](https://github.com/containous/traefik/pull/3093) by [rdrgporto](https://github.com/rdrgporto))
- Fixed documentation urls on README.md ([#3102](https://github.com/containous/traefik/pull/3102) by [emir](https://github.com/emir))
## [v1.6.0-rc3](https://github.com/containous/traefik/tree/v1.6.0-rc3) (2018-03-28)
[All Commits](https://github.com/containous/traefik/compare/v1.6.0-rc2...v1.6.0-rc3)

View File

@@ -160,9 +160,11 @@ Integration tests must be run from the `integration/` directory and require the
The [documentation site](http://docs.traefik.io/) is built with [mkdocs](http://mkdocs.org/)
### Method 1: `Docker` and `make`
### Building Documentation
You can test documentation using the `docs` target.
#### Method 1: `Docker` and `make`
You can build the documentation and serve it locally with livereloading, using the `docs` target:
```bash
$ make docs
@@ -177,11 +179,18 @@ docker run --rm -v /home/user/go/github/containous/traefik:/mkdocs -p 8000:8000
And go to [http://127.0.0.1:8000](http://127.0.0.1:8000).
### Method 2: `mkdocs`
If you only want to build the documentation without serving it locally, you can use the following command:
```bash
$ make docs-build
...
```
#### Method 2: `mkdocs`
First make sure you have python and pip installed
```shell
```bash
$ python --version
Python 2.7.2
$ pip --version
@@ -190,29 +199,49 @@ pip 1.5.2
Then install mkdocs with pip
```shell
```bash
pip install --user -r requirements.txt
```
To test documentation locally run `mkdocs serve` in the root directory, this should start a server locally to preview your changes.
To build documentation locally and serve it locally,
run `mkdocs serve` in the root directory,
this should start a server locally to preview your changes.
```shell
```bash
$ mkdocs serve
INFO - Building documentation...
WARNING - Config value: 'theme'. Warning: The theme 'united' will be removed in an upcoming MkDocs release. See http://www.mkdocs.org/about/release-notes/ for more details
INFO - Cleaning site directory
[I 160505 22:31:24 server:281] Serving on http://127.0.0.1:8000
[I 160505 22:31:24 handlers:59] Start watching changes
[I 160505 22:31:24 handlers:61] Start detecting changes
```
### Verify Documentation
You can verify that the documentation meets some expectations, as checking for dead links, html markup validity.
```bash
$ make docs-verify
docker build -t traefik-docs-verify ./script/docs-verify-docker-image ## Build Validator image
...
docker run --rm -v /home/travis/build/containous/traefik:/app traefik-docs-verify ## Check for dead links and w3c compliance
=== Checking HTML content...
Running ["HtmlCheck", "ImageCheck", "ScriptCheck", "LinkCheck"] on /app/site/basics/index.html on *.html...
```
If you recently changed the documentation, do not forget to clean it to have it rebuilt:
```bash
$ make docs-clean docs-verify
...
```
## How to Write a Good Issue
Please keep in mind that the GitHub issue tracker is not intended as a general support forum, but for reporting bugs and feature requests.
For end-user related support questions, refer to one of the following:
- the Traefik community Slack channel: [![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
- the Traefik community Slack channel: [![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik) (using the `traefik` tag)
### Title

225
Gopkg.lock generated
View File

@@ -3,12 +3,15 @@
[[projects]]
name = "cloud.google.com/go"
packages = [
"compute/metadata",
"internal"
]
revision = "2e6a95edb1071d750f6d7db777bf66cd2997af6c"
version = "v0.7.0"
packages = ["compute/metadata"]
revision = "056a55f54a6cc77b440b31a56a5e7c3982d32811"
version = "v0.22.0"
[[projects]]
branch = "master"
name = "code.cloudfoundry.org/clock"
packages = ["."]
revision = "02e53af36e6c978af692887ed449b74026d76fec"
[[projects]]
branch = "master"
@@ -24,8 +27,12 @@
[[projects]]
name = "github.com/Azure/azure-sdk-for-go"
packages = ["arm/dns"]
revision = "f7bb4db3ea4c73dc58bd284c38ea644a79324be0"
packages = [
"services/dns/mgmt/2017-09-01/dns",
"version"
]
revision = "068ec4d616be5b2175509bf1fb3e4c8ea160d5c8"
version = "v15.0.1"
[[projects]]
branch = "master"
@@ -45,8 +52,8 @@
"autorest/date",
"autorest/to"
]
revision = "f6be1abbb5abd0517522f850dd785990d373da7e"
version = "v9.0.0"
revision = "9ad9326b278af8fa5cc67c30c0ce9a58cc0862b2"
version = "v10.6.0"
[[projects]]
branch = "master"
@@ -79,6 +86,11 @@
packages = ["."]
revision = "e039e20e500c2c025d9145be375e27cf42a94174"
[[projects]]
name = "github.com/Microsoft/ApplicationInsights-Go"
packages = ["appinsights"]
revision = "98ac7ca026c26818888600ea0d966987aa56f043"
[[projects]]
name = "github.com/Microsoft/go-winio"
packages = ["."]
@@ -97,6 +109,12 @@
revision = "a8b993ba6abdb0e0c12b0125c603323a71c7790c"
source = "github.com/ijc25/Gotty"
[[projects]]
branch = "master"
name = "github.com/OpenDNS/vegadns2client"
packages = ["."]
revision = "a3fa4a771d87bda2514a90a157e1fed1b6897d2e"
[[projects]]
name = "github.com/PuerkitoBio/purell"
packages = ["."]
@@ -140,6 +158,17 @@
]
revision = "063d875e3c5fd734fa2aa12fac83829f62acfc70"
[[projects]]
name = "github.com/akamai/AkamaiOPEN-edgegrid-golang"
packages = [
"client-v1",
"configdns-v1",
"edgegrid",
"jsonhooks-v1"
]
revision = "a494eba1efa1f38338393727dff63389a6a66534"
version = "v0.6.0"
[[projects]]
name = "github.com/aokoli/goutils"
packages = ["."]
@@ -177,6 +206,7 @@
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/sdkio",
"internal/sdkrand",
"internal/shareddefaults",
"private/protocol",
@@ -193,11 +223,12 @@
"service/dynamodb/dynamodbiface",
"service/ec2",
"service/ecs",
"service/lightsail",
"service/route53",
"service/sts"
]
revision = "f9a6880d84e16e2a37055793e17164a228d637f4"
version = "v1.13.1"
revision = "fad131ddc707880428615dc8bc1587b55fb46d74"
version = "v1.13.54"
[[projects]]
branch = "master"
@@ -241,14 +272,14 @@
[[projects]]
name = "github.com/containous/staert"
packages = ["."]
revision = "cc00c303ccbd2491ddc1dccc9eb7ccadd807557e"
version = "v3.1.0"
revision = "66717a0e0ca950c4b6dc8c87b46da0b8495c6e41"
version = "v3.1.1"
[[projects]]
name = "github.com/containous/traefik-extra-service-fabric"
packages = ["."]
revision = "29a6d70ad0f15175efbaa5fd93d8afdd8b373b93"
version = "v1.1.1"
revision = "6e90a9eef2ac9d320e55d6e994d169673a8d8b0f"
version = "v1.3.0"
[[projects]]
name = "github.com/coreos/bbolt"
@@ -270,8 +301,8 @@
"pkg/types",
"version"
]
revision = "f1d7dd87da3e8feab4aaf675b8e29c6a5ed5f58b"
version = "v3.2.9"
revision = "70c8726202dd91e482fb4029fd14af1d4ed1d5af"
version = "v3.3.5"
[[projects]]
name = "github.com/coreos/go-semver"
@@ -300,13 +331,14 @@
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
version = "v3.0.0"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
branch = "master"
name = "github.com/dnsimple/dnsimple-go"
packages = ["dnsimple"]
revision = "f2d9b723cc9547d182e24ac2e527ae25d25fc93f"
revision = "bbe1a2c87affea187478e24d3aea3cac25f870b3"
[[projects]]
name = "github.com/docker/cli"
@@ -519,7 +551,7 @@
[[projects]]
name = "github.com/gambol99/go-marathon"
packages = ["."]
revision = "03b46169666c53b9cc953b875ac5714e5103e064"
revision = "99a156b96fb2f9dbe6465affa51bbdccdd37174d"
[[projects]]
name = "github.com/ghodss/yaml"
@@ -553,8 +585,8 @@
"metrics/statsd",
"util/conn"
]
revision = "f66b0e13579bfc5a48b9e2a94b1209c107ea1f41"
version = "v0.3.0"
revision = "ca4112baa34cb55091301bdc13b1420a122b1b9e"
version = "v0.7.0"
[[projects]]
name = "github.com/go-logfmt/logfmt"
@@ -591,7 +623,9 @@
[[projects]]
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
"proto",
"protoc-gen-gogo/descriptor",
"sortkeys"
]
revision = "909568be09de550ed094403c2bf8a261b5bb730a"
@@ -611,7 +645,8 @@
"ptypes/duration",
"ptypes/timestamp"
]
revision = "4bd1920723d7b7c925de087aa32e2187708897f7"
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
@@ -641,11 +676,6 @@
packages = ["."]
revision = "bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5"
[[projects]]
name = "github.com/googleapis/gax-go"
packages = ["."]
revision = "9af46dd5a1713e8b5cd71106287eba3cefdde50b"
[[projects]]
name = "github.com/googleapis/gnostic"
packages = [
@@ -746,6 +776,11 @@
[[projects]]
branch = "master"
name = "github.com/jjcollinge/logrus-appinsights"
packages = ["."]
revision = "9b66602d496a139e4722bdde32f0f1ac1c12d4a8"
[[projects]]
name = "github.com/jjcollinge/servicefabric"
packages = ["."]
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
@@ -914,6 +949,12 @@
packages = ["."]
revision = "db96455566f05ffe42bd6ac671f05eeb1152b45d"
[[projects]]
branch = "master"
name = "github.com/namedotcom/go"
packages = ["namecom"]
revision = "08470befbe04613bd4b44cb6978b05d50294c4d4"
[[projects]]
branch = "master"
name = "github.com/ogier/pflag"
@@ -970,9 +1011,16 @@
revision = "1f5c07e90700ae93ddcba0c7af7d9c7201646ccc"
[[projects]]
branch = "master"
name = "github.com/ovh/go-ovh"
packages = ["ovh"]
revision = "4b1fea467323b74c5f462f0947f402b428ca0626"
revision = "91b7eb631d2eced3e706932a0b36ee8b5ee22e92"
[[projects]]
name = "github.com/patrickmn/go-cache"
packages = ["."]
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
version = "v2.1.0"
[[projects]]
branch = "master"
@@ -986,6 +1034,12 @@
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1"
[[projects]]
name = "github.com/philhofer/fwd"
packages = ["."]
revision = "bb6d471dc95d4fe11e432687f8b70ff496cf3136"
version = "v1.0.0"
[[projects]]
name = "github.com/pierrec/lz4"
packages = ["."]
@@ -1062,6 +1116,17 @@
packages = ["."]
revision = "256dc444b735e061061cf46c809487313d5b0065"
[[projects]]
branch = "master"
name = "github.com/sacloud/libsacloud"
packages = [
".",
"api",
"sacloud",
"sacloud/ostype"
]
revision = "306ea89b6ef19334614f7b0fc5aa19595022bb8c"
[[projects]]
name = "github.com/samuel/go-zookeeper"
packages = ["zk"]
@@ -1120,6 +1185,18 @@
]
revision = "37e84520dcf74488f67654f9c775b9752c232dc1"
[[projects]]
name = "github.com/tinylib/msgp"
packages = ["msgp"]
revision = "b2b6a672cf1e5b90748f79b8b81fc8c5cf0571a1"
version = "1.0.2"
[[projects]]
branch = "master"
name = "github.com/tuvistavie/securerandom"
packages = ["."]
revision = "15512123a948d62f6361bd84818e11f2ad84059a"
[[projects]]
name = "github.com/tv42/zbase32"
packages = ["."]
@@ -1151,7 +1228,8 @@
[[projects]]
name = "github.com/ugorji/go"
packages = ["codec"]
revision = "ea9cd21fa0bc41ee4bdd50ac7ed8cbc7ea2ed960"
revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab"
version = "v1.1.1"
[[projects]]
name = "github.com/unrolled/render"
@@ -1162,7 +1240,7 @@
branch = "v1"
name = "github.com/unrolled/secure"
packages = ["."]
revision = "88720c9cbecfcf2eceb9bb4311ad6e398a8381ed"
revision = "a1cf62cc2159fff407728f118c41aece76c397fa"
[[projects]]
name = "github.com/urfave/negroni"
@@ -1188,7 +1266,7 @@
"roundrobin",
"utils"
]
revision = "dacf34285ce530b272e9fe04d2f45f52e6374e36"
revision = "f0cbb9d6b797d92d168b95b5c443a31dfa67ccd0"
[[projects]]
name = "github.com/vulcand/predicate"
@@ -1214,28 +1292,37 @@
revision = "0c8571ac0ce161a5feb57375a9cdf148c98c0f70"
[[projects]]
branch = "acmev2"
branch = "master"
name = "github.com/xenolf/lego"
packages = [
"acme",
"acmev2",
"log",
"platform/config/env",
"providers/dns",
"providers/dns/auroradns",
"providers/dns/azure",
"providers/dns/bluecat",
"providers/dns/cloudflare",
"providers/dns/cloudxns",
"providers/dns/digitalocean",
"providers/dns/dnsimple",
"providers/dns/dnsmadeeasy",
"providers/dns/dnspod",
"providers/dns/duckdns",
"providers/dns/dyn",
"providers/dns/exec",
"providers/dns/exoscale",
"providers/dns/fastdns",
"providers/dns/gandi",
"providers/dns/gandiv5",
"providers/dns/gcloud",
"providers/dns/glesys",
"providers/dns/godaddy",
"providers/dns/googlecloud",
"providers/dns/lightsail",
"providers/dns/linode",
"providers/dns/namecheap",
"providers/dns/namedotcom",
"providers/dns/nifcloud",
"providers/dns/ns1",
"providers/dns/otc",
"providers/dns/ovh",
@@ -1243,9 +1330,11 @@
"providers/dns/rackspace",
"providers/dns/rfc2136",
"providers/dns/route53",
"providers/dns/sakuracloud",
"providers/dns/vegadns",
"providers/dns/vultr"
]
revision = "a149e7d6506feb4003da7093cbf818c6b75ed4a4"
revision = "e0d512138c43e3f056a41cd7a5beff662ec130d3"
[[projects]]
branch = "master"
@@ -1269,22 +1358,24 @@
"bpf",
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/iana",
"internal/socket",
"internal/socks",
"internal/timeseries",
"ipv4",
"ipv6",
"lex/httplex",
"proxy",
"trace",
"websocket"
]
revision = "22ae77b79946ea320088417e4d50825671d82d57"
revision = "e514e69ffb8bc3c76a71ae40de0118d794855992"
[[projects]]
branch = "master"
name = "golang.org/x/oauth2"
packages = [
".",
@@ -1293,7 +1384,7 @@
"jws",
"jwt"
]
revision = "7fdf09982454086d5570c7db3e11f360194830ca"
revision = "ec22f46f877b4505e0117eeaab541714644fdd28"
[[projects]]
branch = "master"
@@ -1332,6 +1423,7 @@
revision = "8be79e1e0910c292df4e79c241bb7e8f7e725959"
[[projects]]
branch = "master"
name = "google.golang.org/api"
packages = [
"dns/v1",
@@ -1339,7 +1431,7 @@
"googleapi",
"googleapi/internal/uritemplates"
]
revision = "1575df15c1bb8b18ad4d9bc5ca495cc85b0764fe"
revision = "de943baf05a022a8f921b544b7827bacaba1aed5"
[[projects]]
name = "google.golang.org/appengine"
@@ -1366,23 +1458,45 @@
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"channelz",
"codes",
"connectivity",
"credentials",
"grpclb/grpc_lb_v1",
"encoding",
"encoding/proto",
"grpclb/grpc_lb_v1/messages",
"grpclog",
"health/grpc_health_v1",
"internal",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
"transport"
]
revision = "b3ddf786825de56a4178401b7e174ee332173b66"
version = "v1.5.2"
revision = "41344da2231b913fa3d983840a57a6b1b7b631a1"
version = "v1.12.0"
[[projects]]
name = "gopkg.in/DataDog/dd-trace-go.v1"
packages = [
"ddtrace",
"ddtrace/ext",
"ddtrace/internal",
"ddtrace/opentracer",
"ddtrace/tracer"
]
revision = "d052956664af54dbcff2712d10c67c76fbfc299f"
version = "v1.0.0"
[[projects]]
name = "gopkg.in/fsnotify.v1"
@@ -1404,6 +1518,13 @@
version = "v1.30.0"
[[projects]]
branch = "v1"
name = "gopkg.in/mattes/go-expand-tilde.v1"
packages = ["."]
revision = "cb884138e64c9a8bf5c7d6106d74b0fca082df0c"
[[projects]]
branch = "v2"
name = "gopkg.in/ns1/ns1-go.v2"
packages = [
"rest",
@@ -1413,17 +1534,7 @@
"rest/model/filter",
"rest/model/monitor"
]
revision = "c563826f4cbef9c11bebeb9f20a3f7afe9c1e2f4"
[[projects]]
name = "gopkg.in/square/go-jose.v1"
packages = [
".",
"cipher",
"json"
]
revision = "aa2e30fdd1fe9dd3394119af66451ae790d50e0d"
version = "v1.1.0"
revision = "a5bcac82d3f637d3928d30476610891935b2d691"
[[projects]]
name = "gopkg.in/square/go-jose.v2"
@@ -1644,6 +1755,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "593d67272ac35ca0fa59df7f2ac077a81ea842b3181b00acffa20553bfe6f2e0"
inputs-digest = "2b7ffb1d01d8a14224fcc9964900fb5a39fbf38cfacba45f49b931136e4fee9b"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -46,7 +46,7 @@
[[constraint]]
name = "github.com/aws/aws-sdk-go"
version = "1.13.1"
version = "1.13.11"
[[constraint]]
branch = "master"
@@ -62,11 +62,11 @@
[[constraint]]
name = "github.com/containous/staert"
version = "3.1.0"
version = "3.1.1"
[[constraint]]
name = "github.com/containous/traefik-extra-service-fabric"
version = "1.1.1"
version = "1.3.0"
[[constraint]]
name = "github.com/coreos/go-systemd"
@@ -97,7 +97,7 @@
[[constraint]]
name = "github.com/go-kit/kit"
version = "0.3.0"
version = "0.7.0"
[[constraint]]
branch = "master"
@@ -181,8 +181,9 @@
name = "github.com/vulcand/oxy"
[[constraint]]
branch = "acmev2"
branch = "master"
name = "github.com/xenolf/lego"
# version = "1.0.0"
[[constraint]]
name = "google.golang.org/grpc"
@@ -255,3 +256,11 @@
non-go = true
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/patrickmn/go-cache"
version = "2.1.0"
[[constraint]]
name = "gopkg.in/DataDog/dd-trace-go.v1"
version = "1.0.0"

View File

@@ -1,4 +1,4 @@
.PHONY: all
.PHONY: all docs-verify docs docs-clean docs-build
TRAEFIK_ENVS := \
-e OS_ARCH_ARG \
@@ -22,6 +22,7 @@ REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
TRAEFIK_DOC_IMAGE := traefik-docs
TRAEFIK_DOC_VERIFY_IMAGE := $(TRAEFIK_DOC_IMAGE)-verify
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
@@ -94,11 +95,23 @@ image-dirty: binary ## build a docker traefik image
image: clear-static binary ## clean up static directory and build a docker traefik image
docker build -t $(TRAEFIK_IMAGE) .
docs-image:
docker build -t $(TRAEFIK_DOC_IMAGE) -f docs.Dockerfile .
docs: docs-image
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOC_IMAGE) mkdocs serve
docs-image:
docker build -t $(TRAEFIK_DOC_IMAGE) -f docs.Dockerfile .
docs-build: site
docs-verify: site
docker build -t $(TRAEFIK_DOC_VERIFY_IMAGE) ./script/docs-verify-docker-image ## Build Validator image
docker run --rm -v $(CURDIR):/app $(TRAEFIK_DOC_VERIFY_IMAGE) ## Check for dead links and w3c compliance
site: docs-image
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOC_IMAGE) mkdocs build
docs-clean:
rm -rf $(CURDIR)/site
clear-static:
rm -rf static

View File

@@ -8,13 +8,13 @@
[![Go Report Card](https://goreportcard.com/badge/containous/traefik)](http://goreportcard.com/report/containous/traefik)
[![](https://images.microbadger.com/badges/image/traefik.svg)](https://microbadger.com/images/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/containous/traefik/blob/master/LICENSE.md)
[![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
[![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
[![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy)
Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
Telling Træfik where your orchestrator is could be the _only_ configuration step you need to do.
Pointing Træfik at your orchestrator should be the _only_ configuration step you need.
---
@@ -63,25 +63,25 @@ _(But if you'd rather configure some of your routes manually, Træfik supports t
- Websocket, HTTP/2, GRPC ready
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB)
- Keeps access logs (JSON, CLF)
- [Fast](https://docs.traefik.io/benchmarks) ... which is nice
- Fast
- Exposes a Rest API
- Packaged as a single binary file (made with :heart: with go) and available as a [tiny](https://microbadger.com/images/traefik) [official](https://hub.docker.com/r/_/traefik/) docker image
## Supported Backends
- [Docker](docs/configuration/backends/docker/) / [Swarm mode](docs/configuration/backends/docker/#docker-swarm-mode)
- [Kubernetes](docs/configuration/backends/kubernetes/)
- [Mesos](docs/configuration/backends/mesos/) / [Marathon](docs/configuration/backends/marathon/)
- [Rancher](docs/configuration/backends/rancher/) (API, Metadata)
- [Service Fabric](docs/configuration/backends/servicefabric/)
- [Consul Catalog](docs/configuration/backends/consulcatalog/)
- [Consul](docs/configuration/backends/consul/) / [Etcd](docs/configuration/backends/etcd/) / [Zookeeper](docs/configuration/backends/zookeeper/) / [BoltDB](docs/configuration/backends/boltdb/)
- [Eureka](docs/configuration/backends/eureka/)
- [Amazon ECS](docs/configuration/backends/ecs/)
- [Amazon DynamoDB](docs/configuration/backends/dynamodb/)
- [File](docs/configuration/backends/file/)
- [Rest](docs/configuration/backends/rest/)
- [Docker](https://docs.traefik.io/configuration/backends/docker) / [Swarm mode](https://docs.traefik.io/configuration/backends/docker#docker-swarm-mode)
- [Kubernetes](https://docs.traefik.io/configuration/backends/kubernetes)
- [Mesos](https://docs.traefik.io/configuration/backends/mesos) / [Marathon](https://docs.traefik.io/configuration/backends/marathon)
- [Rancher](https://docs.traefik.io/configuration/backends/rancher) (API, Metadata)
- [Azure Service Fabric](https://docs.traefik.io/configuration/backends/servicefabric)
- [Consul Catalog](https://docs.traefik.io/configuration/backends/consulcatalog)
- [Consul](https://docs.traefik.io/configuration/backends/consul) / [Etcd](https://docs.traefik.io/configuration/backends/etcd) / [Zookeeper](https://docs.traefik.io/configuration/backends/zookeeper) / [BoltDB](https://docs.traefik.io/configuration/backends/boltdb)
- [Eureka](https://docs.traefik.io/configuration/backends/eureka)
- [Amazon ECS](https://docs.traefik.io/configuration/backends/ecs)
- [Amazon DynamoDB](https://docs.traefik.io/configuration/backends/dynamodb)
- [File](https://docs.traefik.io/configuration/backends/file)
- [Rest](https://docs.traefik.io/configuration/backends/rest)
## Quickstart
@@ -106,7 +106,7 @@ A collection of contributions around Træfik can be found at [https://awesome.tr
## Support
To get community support, you can:
- join the Træfik community Slack channel: [![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
- join the Træfik community Slack channel: [![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
- use [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik) (using the `traefik` tag)
If you need commercial support, please contact [Containo.us](https://containo.us) by mail: <mailto:support@containo.us>.

View File

@@ -8,14 +8,16 @@ import (
"crypto/x509"
"fmt"
"reflect"
"regexp"
"sort"
"strings"
"sync"
"time"
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/types"
acme "github.com/xenolf/lego/acmev2"
"github.com/xenolf/lego/acme"
)
// Account is used to store lets encrypt registration info
@@ -23,6 +25,7 @@ type Account struct {
Email string
Registration *acme.RegistrationResource
PrivateKey []byte
KeyType acme.KeyType
DomainsCertificate DomainsCertificates
ChallengeCerts map[string]*ChallengeCert
HTTPChallenge map[string]map[string][]byte
@@ -42,6 +45,11 @@ func (a *Account) Init() error {
return err
}
err = a.RemoveAccountV1Values()
if err != nil {
log.Errorf("Unable to remove ACME Account V1 values during account initialization: %v", err)
}
for _, cert := range a.ChallengeCerts {
if cert.certificate == nil {
certificate, err := tls.X509KeyPair(cert.Certificate, cert.PrivateKey)
@@ -63,7 +71,9 @@ func (a *Account) Init() error {
}
// NewAccount creates an account
func NewAccount(email string, certs []*DomainsCertificate) (*Account, error) {
func NewAccount(email string, certs []*DomainsCertificate, keyTypeValue string) (*Account, error) {
keyType := acmeprovider.GetKeyType(keyTypeValue)
// Create a user. New accounts need an email and private key to start
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
@@ -79,6 +89,7 @@ func NewAccount(email string, certs []*DomainsCertificate) (*Account, error) {
return &Account{
Email: email,
PrivateKey: x509.MarshalPKCS1PrivateKey(privateKey),
KeyType: keyType,
DomainsCertificate: DomainsCertificates{Certs: domainsCerts.Certs},
ChallengeCerts: map[string]*ChallengeCert{}}, nil
}
@@ -103,6 +114,29 @@ func (a *Account) GetPrivateKey() crypto.PrivateKey {
return nil
}
// RemoveAccountV1Values removes ACME account V1 values
func (a *Account) RemoveAccountV1Values() error {
// Check if ACME Account is in ACME V1 format
if a.Registration != nil {
isOldRegistration, err := regexp.MatchString(acmeprovider.RegistrationURLPathV1Regexp, a.Registration.URI)
if err != nil {
return err
}
if isOldRegistration {
a.reset()
}
}
return nil
}
func (a *Account) reset() {
log.Debug("Reset ACME account object.")
a.Email = ""
a.Registration = nil
a.PrivateKey = nil
}
// Certificate is used to store certificate info
type Certificate struct {
Domain string
@@ -152,11 +186,23 @@ func (dc *DomainsCertificates) removeDuplicates() {
}
}
func (dc *DomainsCertificates) removeEmpty() {
var certs []*DomainsCertificate
for _, cert := range dc.Certs {
if cert.Certificate != nil && len(cert.Certificate.Certificate) > 0 && len(cert.Certificate.PrivateKey) > 0 {
certs = append(certs, cert)
}
}
dc.Certs = certs
}
// Init DomainsCertificates
func (dc *DomainsCertificates) Init() error {
dc.lock.Lock()
defer dc.lock.Unlock()
dc.removeEmpty()
for _, domainsCertificate := range dc.Certs {
tlsCert, err := tls.X509KeyPair(domainsCertificate.Certificate.Certificate, domainsCertificate.Certificate.PrivateKey)
if err != nil {

View File

@@ -9,7 +9,6 @@ import (
fmtlog "log"
"net"
"net/http"
"os"
"reflect"
"strings"
"time"
@@ -23,10 +22,12 @@ import (
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/tls/generate"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/eapache/channels"
"github.com/xenolf/lego/acmev2"
"github.com/sirupsen/logrus"
"github.com/xenolf/lego/acme"
legolog "github.com/xenolf/lego/log"
"github.com/xenolf/lego/providers/dns"
)
@@ -41,20 +42,23 @@ type ACME struct {
Email string `description:"Email address used for registration"`
Domains []types.Domain `description:"SANs (alternative domains) to each main domain using format: --acme.domains='main.com,san1.com,san2.com' --acme.domains='main.net,san1.net,san2.net'"`
Storage string `description:"File or key used for certificates storage."`
StorageFile string // deprecated
OnDemand bool `description:"Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` //deprecated
StorageFile string // Deprecated
OnDemand bool `description:"(Deprecated) Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` // Deprecated
OnHostRule bool `description:"Enable certificate generation on frontends Host rules."`
CAServer string `description:"CA server to use."`
EntryPoint string `description:"Entrypoint to proxy acme challenge to."`
KeyType string `description:"KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'. Default to 'RSA4096'"`
DNSChallenge *acmeprovider.DNSChallenge `description:"Activate DNS-01 Challenge"`
HTTPChallenge *acmeprovider.HTTPChallenge `description:"Activate HTTP-01 Challenge"`
DNSProvider string `description:"Activate DNS-01 Challenge (Deprecated)"` // deprecated
DelayDontCheckDNS flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // deprecated
TLSChallenge *acmeprovider.TLSChallenge `description:"Activate TLS-ALPN-01 Challenge"`
DNSProvider string `description:"(Deprecated) Activate DNS-01 Challenge"` // Deprecated
DelayDontCheckDNS flaeg.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // Deprecated
ACMELogging bool `description:"Enable debug logging of ACME actions."`
OverrideCertificates bool `description:"Enable to override certificates in key-value store when using storeconfig"`
client *acme.Client
defaultCertificate *tls.Certificate
store cluster.Store
challengeHTTPProvider *challengeHTTPProvider
challengeTLSProvider *challengeTLSProvider
checkOnDemandDomain func(domain string) bool
jobs *channels.InfiniteChannel
TLSConfig *tls.Config `description:"TLS config in case wildcard certs are used"`
@@ -62,31 +66,13 @@ type ACME struct {
}
func (a *ACME) init() error {
// FIXME temporary fix, waiting for https://github.com/xenolf/lego/pull/478
acme.HTTPClient = http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 15 * time.Second,
ResponseHeaderTimeout: 15 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
acme.UserAgent = fmt.Sprintf("containous-traefik/%s", version.Version)
if a.ACMELogging {
acme.Logger = fmtlog.New(os.Stderr, "legolog: ", fmtlog.LstdFlags)
legolog.Logger = fmtlog.New(log.WriterLevel(logrus.InfoLevel), "legolog: ", 0)
} else {
acme.Logger = fmtlog.New(ioutil.Discard, "", 0)
legolog.Logger = fmtlog.New(ioutil.Discard, "", 0)
}
// no certificates in TLS config, so we add a default one
cert, err := generate.DefaultCertificate()
if err != nil {
return err
}
a.defaultCertificate = cert
a.jobs = channels.NewInfiniteChannel()
return nil
@@ -126,14 +112,18 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl
if err != nil {
return err
}
if len(a.Storage) == 0 {
return errors.New("Empty Store, please provide a key for certs storage")
return errors.New("empty Store, please provide a key for certs storage")
}
a.checkOnDemandDomain = checkOnDemandDomain
a.dynamicCerts = certs
tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate)
a.challengeTLSProvider = &challengeTLSProvider{store: a.store}
tlsConfig.GetCertificate = a.getCertificate
a.TLSConfig = tlsConfig
listener := func(object cluster.Object) error {
account := object.(*Account)
account.Init()
@@ -192,6 +182,10 @@ func (a *ACME) leadershipListener(elected bool) error {
account := object.(*Account)
account.Init()
// Reset Account values if caServer changed, thus registration URI can be updated
if account != nil && account.Registration != nil && !strings.HasPrefix(account.Registration.URI, a.CAServer) {
account.reset()
}
var needRegister bool
if account == nil || len(account.Email) == 0 {
@@ -200,7 +194,7 @@ func (a *ACME) leadershipListener(elected bool) error {
domainsCerts = account.DomainsCertificate
}
account, err = NewAccount(a.Email, domainsCerts.Certs)
account, err = NewAccount(a.Email, domainsCerts.Certs, a.KeyType)
if err != nil {
return err
}
@@ -240,6 +234,11 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
domain := types.CanonicalDomain(clientHello.ServerName)
account := a.store.Get().(*Account)
if challengeCert, ok := a.challengeTLSProvider.getCertificate(domain); ok {
log.Debugf("ACME got challenge %s", domain)
return challengeCert, nil
}
if providedCertificate := a.getProvidedCertificate(domain); providedCertificate != nil {
return providedCertificate, nil
}
@@ -248,12 +247,14 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
log.Debugf("ACME got domain cert %s", domain)
return domainCert.tlsCert, nil
}
if a.OnDemand {
if a.checkOnDemandDomain != nil && !a.checkOnDemandDomain(domain) {
return nil, nil
}
return a.loadCertificateOnDemand(clientHello)
}
log.Debugf("No certificate found or generated for %s", domain)
return nil, nil
}
@@ -409,11 +410,13 @@ func (a *ACME) buildACMEClient(account *Account) (*acme.Client, error) {
if len(a.CAServer) > 0 {
caServer = a.CAServer
}
client, err := acme.NewClient(caServer, account, acme.RSA4096)
client, err := acme.NewClient(caServer, account, account.KeyType)
if err != nil {
return nil, err
}
// DNS challenge
if a.DNSChallenge != nil && len(a.DNSChallenge.Provider) > 0 {
log.Debugf("Using DNS Challenge provider: %s", a.DNSChallenge.Provider)
@@ -428,21 +431,30 @@ func (a *ACME) buildACMEClient(account *Account) (*acme.Client, error) {
return nil, err
}
client.ExcludeChallenges([]acme.Challenge{acme.HTTP01})
client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.TLSALPN01})
err = client.SetChallengeProvider(acme.DNS01, provider)
} else if a.HTTPChallenge != nil && len(a.HTTPChallenge.EntryPoint) > 0 {
log.Debug("Using HTTP Challenge provider.")
client.ExcludeChallenges([]acme.Challenge{acme.DNS01})
a.challengeHTTPProvider = &challengeHTTPProvider{store: a.store}
err = client.SetChallengeProvider(acme.HTTP01, a.challengeHTTPProvider)
} else {
return nil, errors.New("ACME challenge not specified, please select HTTP or DNS Challenge")
return client, err
}
if err != nil {
return nil, err
// HTTP challenge
if a.HTTPChallenge != nil && len(a.HTTPChallenge.EntryPoint) > 0 {
log.Debug("Using HTTP Challenge provider.")
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01})
a.challengeHTTPProvider = &challengeHTTPProvider{store: a.store}
err = client.SetChallengeProvider(acme.HTTP01, a.challengeHTTPProvider)
return client, err
}
return client, nil
// TLS Challenge
if a.TLSChallenge != nil {
log.Debug("Using TLS Challenge provider.")
client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.DNS01})
err = client.SetChallengeProvider(acme.TLSALPN01, a.challengeTLSProvider)
return client, err
}
return nil, errors.New("ACME challenge not specified, please select TLS or HTTP or DNS Challenge")
}
func (a *ACME) loadCertificateOnDemand(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
@@ -625,11 +637,12 @@ func (a *ACME) getDomainsCertificates(domains []string) (*Certificate, error) {
domains = fun.Map(types.CanonicalDomain, domains).([]string)
log.Debugf("Loading ACME certificates %s...", domains)
bundle := true
certificate, failures := a.client.ObtainCertificate(domains, bundle, nil, OSCPMustStaple)
if len(failures) > 0 {
log.Error(failures)
return nil, fmt.Errorf("cannot obtain certificates %+v", failures)
certificate, err := a.client.ObtainCertificate(domains, bundle, nil, OSCPMustStaple)
if err != nil {
return nil, fmt.Errorf("cannot obtain certificates: %+v", err)
}
log.Debugf("Loaded ACME certificates %s", domains)
return &Certificate{
Domain: certificate.Domain,
@@ -651,6 +664,7 @@ func (a *ACME) runJobs() {
// getValidDomains checks if given domain is allowed to generate a ACME certificate and return it
func (a *ACME) getValidDomains(domains []string, wildcardAllowed bool) ([]string, error) {
// Check if the domains array is empty or contains only one empty value
if len(domains) == 0 || (len(domains) == 1 && len(domains[0]) == 0) {
return nil, errors.New("unable to generate a certificate when no domain is given")
}
@@ -663,15 +677,14 @@ func (a *ACME) getValidDomains(domains []string, wildcardAllowed bool) ([]string
if a.DNSChallenge == nil && len(a.DNSProvider) == 0 {
return nil, fmt.Errorf("unable to generate a wildcard certificate for domain %q : ACME needs a DNSChallenge", strings.Join(domains, ","))
}
if len(domains) > 1 {
return nil, fmt.Errorf("unable to generate a wildcard certificate for domain %q : SANs are not allowed", strings.Join(domains, ","))
if strings.HasPrefix(domains[0], "*.*") {
return nil, fmt.Errorf("unable to generate a wildcard certificate for domain %q : ACME does not allow '*.*' wildcard domain", strings.Join(domains, ","))
}
} else {
for _, san := range domains[1:] {
if strings.HasPrefix(san, "*") {
return nil, fmt.Errorf("unable to generate a certificate in ACME provider for domains %q: SANs can not be a wildcard domain", strings.Join(domains, ","))
}
}
for _, san := range domains[1:] {
if strings.HasPrefix(san, "*") {
return nil, fmt.Errorf("unable to generate a certificate for domains %q: SANs can not be a wildcard domain", strings.Join(domains, ","))
}
}
@@ -710,31 +723,37 @@ func (a *ACME) deleteUnnecessaryDomains() {
keepDomain = false
}
break
} else if strings.HasPrefix(domain.Main, "*") && domain.SANs == nil {
// Check if domains can be validated by the wildcard domain
var newDomainsToCheck []string
// Check if domains can be validated by the wildcard domain
domainsMap := make(map[string]*tls.Certificate)
domainsMap[domain.Main] = &tls.Certificate{}
for _, domainProcessed := range domainToCheck.ToStrArray() {
if isDomainAlreadyChecked(domainProcessed, domainsMap) {
log.Warnf("Domain %q will not be processed by ACME because it is validated by the wildcard %q", domainProcessed, domain.Main)
continue
}
newDomainsToCheck = append(newDomainsToCheck, domainProcessed)
}
// Delete the domain if both Main and SANs can be validated by the wildcard domain
// otherwise keep the unchecked values
if newDomainsToCheck == nil {
keepDomain = false
break
}
domainToCheck.Set(newDomainsToCheck)
}
var newDomainsToCheck []string
// Check if domains can be validated by the wildcard domain
domainsMap := make(map[string]*tls.Certificate)
domainsMap[domain.Main] = &tls.Certificate{}
if len(domain.SANs) > 0 {
domainsMap[strings.Join(domain.SANs, ",")] = &tls.Certificate{}
}
for _, domainProcessed := range domainToCheck.ToStrArray() {
if idxDomain < idxDomainToCheck && isDomainAlreadyChecked(domainProcessed, domainsMap) {
// The domain is duplicated in a CN
log.Warnf("Domain %q is duplicated in the configuration or validated by the domain %v. It will be processed once.", domainProcessed, domain)
continue
} else if domain.Main != domainProcessed && strings.HasPrefix(domain.Main, "*") && types.MatchDomain(domainProcessed, domain.Main) {
// Check if a wildcard can validate the domain
log.Warnf("Domain %q will not be processed by ACME provider because it is validated by the wildcard %q", domainProcessed, domain.Main)
continue
}
newDomainsToCheck = append(newDomainsToCheck, domainProcessed)
}
// Delete the domain if both Main and SANs can be validated by the wildcard domain
// otherwise keep the unchecked values
if newDomainsToCheck == nil {
keepDomain = false
break
}
domainToCheck.Set(newDomainsToCheck)
}
if keepDomain {

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"sort"
"sync"
"testing"
"time"
@@ -14,7 +15,7 @@ import (
"github.com/containous/traefik/tls/generate"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
"github.com/xenolf/lego/acmev2"
"github.com/xenolf/lego/acme"
)
func TestDomainsSet(t *testing.T) {
@@ -417,11 +418,27 @@ func TestAcme_getValidDomain(t *testing.T) {
expectedDomains: nil,
},
{
desc: "unexpected SANs",
domains: []string{"*.traefik.wtf", "foo.traefik.wtf"},
desc: "unauthorized wildcard with SAN",
domains: []string{"*.*.traefik.wtf", "foo.traefik.wtf"},
dnsChallenge: &acmeprovider.DNSChallenge{},
wildcardAllowed: true,
expectedErr: "unable to generate a wildcard certificate for domain \"*.traefik.wtf,foo.traefik.wtf\" : SANs are not allowed",
expectedErr: "unable to generate a wildcard certificate for domain \"*.*.traefik.wtf,foo.traefik.wtf\" : ACME does not allow '*.*' wildcard domain",
expectedDomains: nil,
},
{
desc: "wildcard with SANs",
domains: []string{"*.traefik.wtf", "traefik.wtf"},
dnsChallenge: &acmeprovider.DNSChallenge{},
wildcardAllowed: true,
expectedErr: "",
expectedDomains: []string{"*.traefik.wtf", "traefik.wtf"},
},
{
desc: "unexpected SANs",
domains: []string{"*.traefik.wtf", "*.acme.wtf"},
dnsChallenge: &acmeprovider.DNSChallenge{},
wildcardAllowed: true,
expectedErr: "unable to generate a certificate for domains \"*.traefik.wtf,*.acme.wtf\": SANs can not be a wildcard domain",
expectedDomains: nil,
},
}
@@ -534,3 +551,268 @@ func TestAcme_getCertificateForDomain(t *testing.T) {
})
}
}
func TestRemoveEmptyCertificates(t *testing.T) {
now := time.Now()
fooCert, fooKey, _ := generate.KeyPair("foo.com", now)
acmeCert, acmeKey, _ := generate.KeyPair("acme.wtf", now.Add(24*time.Hour))
barCert, barKey, _ := generate.KeyPair("bar.com", now)
testCases := []struct {
desc string
dc *DomainsCertificates
expectedDc *DomainsCertificates
}{
{
desc: "No empty certificate",
dc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: fooCert,
PrivateKey: fooKey,
},
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{
Certificate: barCert,
PrivateKey: barKey,
},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
expectedDc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: fooCert,
PrivateKey: fooKey,
},
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{
Certificate: barCert,
PrivateKey: barKey,
},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
},
{
desc: "First certificate is nil",
dc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{
Certificate: barCert,
PrivateKey: barKey,
},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
expectedDc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{
Certificate: nil,
PrivateKey: barKey,
},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
},
{
desc: "Last certificate is empty",
dc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: fooCert,
PrivateKey: fooKey,
},
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
expectedDc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: fooCert,
PrivateKey: fooKey,
},
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
},
},
},
{
desc: "First and last certificates are nil or empty",
dc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Domains: types.Domain{
Main: "foo.com",
},
},
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
{
Certificate: &Certificate{},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
expectedDc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Certificate: &Certificate{
Certificate: acmeCert,
PrivateKey: acmeKey,
},
Domains: types.Domain{
Main: "acme.wtf",
},
},
},
},
},
{
desc: "All certificates are nil or empty",
dc: &DomainsCertificates{
Certs: []*DomainsCertificate{
{
Domains: types.Domain{
Main: "foo.com",
},
},
{
Domains: types.Domain{
Main: "foo24.com",
},
},
{
Certificate: &Certificate{},
Domains: types.Domain{
Main: "bar.com",
},
},
},
},
expectedDc: &DomainsCertificates{
Certs: []*DomainsCertificate{},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
a := &Account{DomainsCertificate: *test.dc}
a.Init()
assert.Equal(t, len(test.expectedDc.Certs), len(a.DomainsCertificate.Certs))
sort.Sort(&a.DomainsCertificate)
sort.Sort(test.expectedDc)
for key, value := range test.expectedDc.Certs {
assert.Equal(t, value.Domains.Main, a.DomainsCertificate.Certs[key].Domains.Main)
}
})
}
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
"github.com/containous/traefik/safe"
acme "github.com/xenolf/lego/acmev2"
"github.com/xenolf/lego/acme"
)
var _ acme.ChallengeProviderTimeout = (*challengeHTTPProvider)(nil)
@@ -23,10 +23,12 @@ func (c *challengeHTTPProvider) getTokenValue(token, domain string) []byte {
log.Debugf("Looking for an existing ACME challenge for token %v...", token)
c.lock.RLock()
defer c.lock.RUnlock()
account := c.store.Get().(*Account)
if account.HTTPChallenge == nil {
return []byte{}
}
var result []byte
operation := func() error {
var ok bool
@@ -35,9 +37,11 @@ func (c *challengeHTTPProvider) getTokenValue(token, domain string) []byte {
}
return nil
}
notify := func(err error, time time.Duration) {
log.Errorf("Error getting challenge for token retrying in %s", time)
}
ebo := backoff.NewExponentialBackOff()
ebo.MaxElapsedTime = 60 * time.Second
err := backoff.RetryNotify(safe.OperationWithRecover(operation), ebo, notify)
@@ -52,18 +56,23 @@ func (c *challengeHTTPProvider) Present(domain, token, keyAuth string) error {
log.Debugf("Challenge Present %s", domain)
c.lock.Lock()
defer c.lock.Unlock()
transaction, object, err := c.store.Begin()
if err != nil {
return err
}
account := object.(*Account)
if account.HTTPChallenge == nil {
account.HTTPChallenge = map[string]map[string][]byte{}
}
if _, ok := account.HTTPChallenge[token]; !ok {
account.HTTPChallenge[token] = map[string][]byte{}
}
account.HTTPChallenge[token][domain] = []byte(keyAuth)
return transaction.Commit(account)
}
@@ -71,10 +80,12 @@ func (c *challengeHTTPProvider) CleanUp(domain, token, keyAuth string) error {
log.Debugf("Challenge CleanUp %s", domain)
c.lock.Lock()
defer c.lock.Unlock()
transaction, object, err := c.store.Begin()
if err != nil {
return err
}
account := object.(*Account)
if _, ok := account.HTTPChallenge[token]; ok {
if _, domainOk := account.HTTPChallenge[token][domain]; domainOk {
@@ -84,6 +95,7 @@ func (c *challengeHTTPProvider) CleanUp(domain, token, keyAuth string) error {
delete(account.HTTPChallenge, token)
}
}
return transaction.Commit(account)
}

View File

@@ -0,0 +1,127 @@
package acme
import (
"crypto/tls"
"fmt"
"strings"
"sync"
"time"
"github.com/cenk/backoff"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
"github.com/containous/traefik/safe"
"github.com/xenolf/lego/acme"
)
var _ acme.ChallengeProviderTimeout = (*challengeTLSProvider)(nil)
type challengeTLSProvider struct {
store cluster.Store
lock sync.RWMutex
}
func (c *challengeTLSProvider) getCertificate(domain string) (cert *tls.Certificate, exists bool) {
log.Debugf("Looking for an existing ACME challenge for %s...", domain)
if !strings.HasSuffix(domain, ".acme.invalid") {
return nil, false
}
c.lock.RLock()
defer c.lock.RUnlock()
account := c.store.Get().(*Account)
if account.ChallengeCerts == nil {
return nil, false
}
account.Init()
var result *tls.Certificate
operation := func() error {
for _, cert := range account.ChallengeCerts {
for _, dns := range cert.certificate.Leaf.DNSNames {
if domain == dns {
result = cert.certificate
return nil
}
}
}
return fmt.Errorf("cannot find challenge cert for domain %s", domain)
}
notify := func(err error, time time.Duration) {
log.Errorf("Error getting cert: %v, retrying in %s", err, time)
}
ebo := backoff.NewExponentialBackOff()
ebo.MaxElapsedTime = 60 * time.Second
err := backoff.RetryNotify(safe.OperationWithRecover(operation), ebo, notify)
if err != nil {
log.Errorf("Error getting cert: %v", err)
return nil, false
}
return result, true
}
func (c *challengeTLSProvider) Present(domain, token, keyAuth string) error {
log.Debugf("Challenge Present %s", domain)
cert, err := tlsALPN01ChallengeCert(domain, keyAuth)
if err != nil {
return err
}
c.lock.Lock()
defer c.lock.Unlock()
transaction, object, err := c.store.Begin()
if err != nil {
return err
}
account := object.(*Account)
if account.ChallengeCerts == nil {
account.ChallengeCerts = map[string]*ChallengeCert{}
}
account.ChallengeCerts[domain] = cert
return transaction.Commit(account)
}
func (c *challengeTLSProvider) CleanUp(domain, token, keyAuth string) error {
log.Debugf("Challenge CleanUp %s", domain)
c.lock.Lock()
defer c.lock.Unlock()
transaction, object, err := c.store.Begin()
if err != nil {
return err
}
account := object.(*Account)
delete(account.ChallengeCerts, domain)
return transaction.Commit(account)
}
func (c *challengeTLSProvider) Timeout() (timeout, interval time.Duration) {
return 60 * time.Second, 5 * time.Second
}
func tlsALPN01ChallengeCert(domain, keyAuth string) (*ChallengeCert, error) {
tempCertPEM, rsaPrivPEM, err := acme.TLSALPNChallengeBlocks(domain, keyAuth)
if err != nil {
return nil, err
}
certificate, err := tls.X509KeyPair(tempCertPEM, rsaPrivPEM)
if err != nil {
return nil, err
}
return &ChallengeCert{Certificate: tempCertPEM, PrivateKey: rsaPrivPEM, certificate: &certificate}, nil
}

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"io/ioutil"
"os"
"regexp"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/acme"
@@ -26,7 +25,7 @@ func NewLocalStore(file string) *LocalStore {
func (s *LocalStore) Get() (*Account, error) {
account := &Account{}
hasData, err := checkFile(s.file)
hasData, err := acme.CheckFile(s.file)
if err != nil {
return nil, err
}
@@ -46,20 +45,6 @@ func (s *LocalStore) Get() (*Account, error) {
if err := json.Unmarshal(file, &account); err != nil {
return nil, err
}
// Check if ACME Account is in ACME V1 format
if account != nil && account.Registration != nil {
isOldRegistration, err := regexp.MatchString(acme.RegistrationURLPathV1Regexp, account.Registration.URI)
if err != nil {
return nil, err
}
if isOldRegistration {
account.Email = ""
account.Registration = nil
account.PrivateKey = nil
}
}
}
return account, nil
@@ -71,13 +56,13 @@ func ConvertToNewFormat(fileName string) {
storeAccount, err := localStore.GetAccount()
if err != nil {
log.Warnf("Failed to read new account, ACME data conversion is not available : %v", err)
log.Errorf("Failed to read new account, ACME data conversion is not available : %v", err)
return
}
storeCertificates, err := localStore.GetCertificates()
if err != nil {
log.Warnf("Failed to read new certificates, ACME data conversion is not available : %v", err)
log.Errorf("Failed to read new certificates, ACME data conversion is not available : %v", err)
return
}
@@ -86,17 +71,30 @@ func ConvertToNewFormat(fileName string) {
account, err := localStore.Get()
if err != nil {
log.Warnf("Failed to read old account, ACME data conversion is not available : %v", err)
log.Errorf("Failed to read old account, ACME data conversion is not available : %v", err)
return
}
// Convert ACME data from old to new format
newAccount := &acme.Account{}
if account != nil && len(account.Email) > 0 {
err = backupACMEFile(fileName, account)
if err != nil {
log.Errorf("Unable to create a backup for the V1 formatted ACME file: %v", err)
return
}
err = account.RemoveAccountV1Values()
if err != nil {
log.Errorf("Unable to remove ACME Account V1 values during format conversion: %v", err)
return
}
newAccount = &acme.Account{
PrivateKey: account.PrivateKey,
Registration: account.Registration,
Email: account.Email,
KeyType: account.KeyType,
}
var newCertificates []*acme.Certificate
@@ -107,8 +105,8 @@ func ConvertToNewFormat(fileName string) {
Domain: cert.Domains,
})
}
// If account is in the old format, storeCertificates is nil or empty
// and has to be initialized
// If account is in the old format, storeCertificates is nil or empty and has to be initialized
storeCertificates = newCertificates
}
@@ -119,7 +117,16 @@ func ConvertToNewFormat(fileName string) {
}
}
// FromNewToOldFormat converts new acme.json format to the old one (used for the backward compatibility)
func backupACMEFile(originalFileName string, account interface{}) error {
// write account to file
data, err := json.MarshalIndent(account, "", " ")
if err != nil {
return err
}
return ioutil.WriteFile(originalFileName+".bak", data, 0600)
}
// FromNewToOldFormat converts new acme account to the old one (used for the backward compatibility)
func FromNewToOldFormat(fileName string) (*Account, error) {
localStore := acme.NewLocalStore(fileName)
@@ -142,6 +149,7 @@ func FromNewToOldFormat(fileName string) (*Account, error) {
PrivateKey: storeAccount.PrivateKey,
Registration: storeAccount.Registration,
DomainsCertificate: DomainsCertificates{},
KeyType: storeAccount.KeyType,
}
}

View File

@@ -4,19 +4,36 @@ import (
"net/http"
"github.com/containous/mux"
"github.com/containous/traefik/autogen/genstatic"
"github.com/containous/traefik/log"
"github.com/elazarl/go-bindata-assetfs"
)
// DashboardHandler expose dashboard routes
type DashboardHandler struct{}
type DashboardHandler struct {
Assets *assetfs.AssetFS
}
// AddRoutes add dashboard routes on a router
func (g DashboardHandler) AddRoutes(router *mux.Router) {
if g.Assets == nil {
log.Error("No assets for dashboard")
return
}
// 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/", 302)
})
router.Methods(http.MethodGet).PathPrefix("/dashboard/").
Handler(http.StripPrefix("/dashboard/", http.FileServer(&assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"})))
router.Methods(http.MethodGet).
Path("/").
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
http.Redirect(response, request, request.Header.Get("X-Forwarded-Prefix")+"/dashboard/", 302)
})
router.Methods(http.MethodGet).
Path("/dashboard/status").
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
http.Redirect(response, request, "/dashboard/", 302)
})
router.Methods(http.MethodGet).
PathPrefix("/dashboard/").
Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets)))
}

View File

@@ -38,6 +38,8 @@ func (g DebugHandler) AddRoutes(router *mux.Router) {
fmt.Fprint(w, "\n}\n")
})
runtime.SetBlockProfileRate(1)
runtime.SetMutexProfileFraction(5)
router.Methods(http.MethodGet).PathPrefix("/debug/pprof/cmdline").HandlerFunc(pprof.Cmdline)
router.Methods(http.MethodGet).PathPrefix("/debug/pprof/profile").HandlerFunc(pprof.Profile)
router.Methods(http.MethodGet).PathPrefix("/debug/pprof/symbol").HandlerFunc(pprof.Symbol)

View File

@@ -9,6 +9,7 @@ import (
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/elazarl/go-bindata-assetfs"
thoas_stats "github.com/thoas/stats"
"github.com/unrolled/render"
)
@@ -22,6 +23,7 @@ type Handler struct {
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
Stats *thoas_stats.Stats `json:"-"`
StatsRecorder *middlewares.StatsRecorder `json:"-"`
DashboardAssets *assetfs.AssetFS
}
var (
@@ -54,7 +56,7 @@ func (p Handler) AddRoutes(router *mux.Router) {
version.Handler{}.AddRoutes(router)
if p.Dashboard {
DashboardHandler{}.AddRoutes(router)
DashboardHandler{Assets: p.DashboardAssets}.AddRoutes(router)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -152,7 +152,7 @@ func (d *Datastore) Begin() (Transaction, Object, error) {
operation := func() error {
meta := d.get()
if meta.Lock != id {
return fmt.Errorf("Object lock value: expected %s, got %s", id, meta.Lock)
return fmt.Errorf("object lock value: expected %s, got %s", id, meta.Lock)
}
return nil
}
@@ -167,7 +167,7 @@ func (d *Datastore) Begin() (Transaction, Object, error) {
ebo.MaxElapsedTime = 60 * time.Second
err = backoff.RetryNotify(safe.OperationWithRecover(operation), ebo, notify)
if err != nil {
return nil, nil, fmt.Errorf("Datastore cannot sync: %v", err)
return nil, nil, fmt.Errorf("datastore cannot sync: %v", err)
}
// we synced with KV store, we can now return Setter
@@ -224,12 +224,12 @@ func (s *datastoreTransaction) Commit(object Object) error {
s.localLock.Lock()
defer s.localLock.Unlock()
if s.dirty {
return fmt.Errorf("Transaction already used, please begin a new one")
return fmt.Errorf("transaction already used, please begin a new one")
}
s.Datastore.meta.object = object
err := s.Datastore.meta.Marshall()
if err != nil {
return fmt.Errorf("Marshall error: %s", err)
return fmt.Errorf("marshall error: %s", err)
}
err = s.kv.StoreConfig(s.Datastore.meta)
if err != nil {
@@ -238,7 +238,7 @@ func (s *datastoreTransaction) Commit(object Object) error {
err = s.remoteLock.Unlock()
if err != nil {
return fmt.Errorf("Unlock error: %s", err)
return fmt.Errorf("unlock error: %s", err)
}
s.dirty = true

View File

@@ -14,6 +14,8 @@ import (
"github.com/unrolled/render"
)
const clusterLeaderKeySuffix = "/leader"
var templatesRenderer = render.New(render.Options{
Directory: "nowhere",
})
@@ -32,7 +34,7 @@ func NewLeadership(ctx context.Context, cluster *types.Cluster) *Leadership {
return &Leadership{
Pool: safe.NewPool(ctx),
Cluster: cluster,
candidate: leadership.NewCandidate(cluster.Store, cluster.Store.Prefix+"/leader", cluster.Node, 20*time.Second),
candidate: leadership.NewCandidate(cluster.Store, cluster.Store.Prefix+clusterLeaderKeySuffix, cluster.Node, 20*time.Second),
listeners: []LeaderListener{},
leader: safe.New(false),
}
@@ -106,11 +108,19 @@ func (l *Leadership) onElection(elected bool) {
}
type leaderResponse struct {
Leader bool `json:"leader"`
Leader bool `json:"leader"`
LeaderNode string `json:"leader_node"`
}
func (l *Leadership) getLeaderHandler(response http.ResponseWriter, request *http.Request) {
leader := &leaderResponse{Leader: l.IsLeader()}
leaderNode := ""
leaderKv, err := l.Cluster.Store.Get(l.Cluster.Store.Prefix+clusterLeaderKeySuffix, nil)
if err != nil {
log.Error(err)
} else {
leaderNode = string(leaderKv.Value)
}
leader := &leaderResponse{Leader: l.IsLeader(), LeaderNode: leaderNode}
status := http.StatusOK
if !leader.Leader {
@@ -118,7 +128,7 @@ func (l *Leadership) getLeaderHandler(response http.ResponseWriter, request *htt
status = http.StatusTooManyRequests
}
err := templatesRenderer.JSON(response, status, leader)
err = templatesRenderer.JSON(response, status, leader)
if err != nil {
log.Error(err)
}

View File

@@ -23,7 +23,7 @@ The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://traefik.herokuapp.com
- the Traefik community Slack channel: https://slack.traefik.io
-->
@@ -31,7 +31,7 @@ For end-user related support questions, refer to one of the following:
(If you intend to ask a support question: **DO NOT FILE AN ISSUE**.
Use [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik)
or [Slack](https://traefik.herokuapp.com) instead.)
or [Slack](https://slack.traefik.io) instead.)
@@ -88,7 +88,7 @@ Add more configuration information here.
// NewCmd builds a new Bug command
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
//version Command init
// version Command init
return &flaeg.Command{
Name: "bug",
Description: `Report an issue on Traefik bugtracker`,

View File

@@ -78,6 +78,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
},
InfluxDB: &types.InfluxDB{
Address: "localhost:8089",
Protocol: "udp",
PushInterval: "10s",
},
}
@@ -88,7 +89,9 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
defaultMarathon.ExposedByDefault = true
defaultMarathon.Constraints = types.Constraints{}
defaultMarathon.DialerTimeout = flaeg.Duration(60 * time.Second)
defaultMarathon.DialerTimeout = flaeg.Duration(5 * time.Second)
defaultMarathon.ResponseHeaderTimeout = flaeg.Duration(60 * time.Second)
defaultMarathon.TLSHandshakeTimeout = flaeg.Duration(5 * time.Second)
defaultMarathon.KeepAlive = flaeg.Duration(10 * time.Second)
// default Consul
@@ -105,6 +108,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
defaultConsulCatalog.Constraints = types.Constraints{}
defaultConsulCatalog.Prefix = "traefik"
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
defaultConsulCatalog.Stale = false
// default Etcd
var defaultEtcd etcd.Provider
@@ -220,7 +224,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6832",
LocalAgentHostPort: "127.0.0.1:6831",
},
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
@@ -260,10 +264,17 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
},
InfluxDB: &types.InfluxDB{
Address: "localhost:8089",
Protocol: "udp",
PushInterval: "10s",
},
}
defaultResolver := configuration.HostResolverConfig{
CnameFlattening: false,
ResolvConfig: "/etc/resolv.conf",
ResolvDepth: 5,
}
defaultConfiguration := configuration.GlobalConfiguration{
Docker: &defaultDocker,
File: &defaultFile,
@@ -292,6 +303,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
API: &defaultAPI,
Metrics: &defaultMetrics,
Tracing: &defaultTracing,
HostResolver: &defaultResolver,
}
return &TraefikConfiguration{

View File

@@ -85,21 +85,26 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
}
}
// Store the ACME Account into the KV Store
meta := cluster.NewMetadata(account)
err = meta.Marshall()
if err != nil {
return err
}
// Check to see if ACME account object is already in kv store
if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates {
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
}
// Store the ACME Account into the KV Store
// Certificates in KV Store will be overridden
meta := cluster.NewMetadata(account)
err = meta.Marshall()
if err != nil {
return err
}
err = source.StoreConfig(meta)
if err != nil {
return err
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
}
err = source.StoreConfig(meta)
if err != nil {
return err
}
}
// Force to delete storagefile
@@ -134,10 +139,16 @@ func migrateACMEData(fileName string) (*acme.Account, error) {
if accountFromNewFormat == nil {
// convert ACME json file to KV store (used for backward compatibility)
localStore := acme.NewLocalStore(fileName)
account, err = localStore.Get()
if err != nil {
return nil, err
}
err = account.RemoveAccountV1Values()
if err != nil {
return nil, err
}
} else {
account = accountFromNewFormat
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/cenk/backoff"
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/autogen/genstatic"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/cmd/bug"
"github.com/containous/traefik/cmd/healthcheck"
@@ -21,9 +22,9 @@ import (
cmdVersion "github.com/containous/traefik/cmd/version"
"github.com/containous/traefik/collector"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/configuration/router"
"github.com/containous/traefik/job"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/safe"
@@ -33,8 +34,10 @@ import (
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/coreos/go-systemd/daemon"
"github.com/elazarl/go-bindata-assetfs"
"github.com/ogier/pflag"
"github.com/sirupsen/logrus"
"github.com/vulcand/oxy/roundrobin"
)
func main() {
@@ -155,9 +158,17 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
if globalConfiguration.AllowMinWeightZero {
roundrobin.SetDefaultWeight(0)
}
globalConfiguration.SetEffectiveConfiguration(configFile)
globalConfiguration.ValidateConfiguration()
if globalConfiguration.API != nil && globalConfiguration.API.Dashboard {
globalConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
}
jsonConf, _ := json.Marshal(globalConfiguration)
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
@@ -168,16 +179,60 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
stats(globalConfiguration)
log.Debugf("Global configuration loaded %s", string(jsonConf))
if acme.IsEnabled() {
store := acme.NewLocalStore(acme.Get().Storage)
acme.Get().Store = &store
providerAggregator := configuration.NewProviderAggregator(globalConfiguration)
acmeprovider := globalConfiguration.InitACMEProvider()
if acmeprovider != nil {
err := providerAggregator.AddProvider(acmeprovider)
if err != nil {
log.Errorf("Error initializing provider ACME: %v", err)
acmeprovider = nil
}
}
svr := server.NewServer(*globalConfiguration, configuration.NewProviderAggregator(globalConfiguration))
if acme.IsEnabled() && acme.Get().OnHostRule {
acme.Get().SetConfigListenerChan(make(chan types.Configuration))
svr.AddListener(acme.Get().ListenConfiguration)
entryPoints := map[string]server.EntryPoint{}
for entryPointName, config := range globalConfiguration.EntryPoints {
entryPoint := server.EntryPoint{
Configuration: config,
}
internalRouter := router.NewInternalRouterAggregator(*globalConfiguration, entryPointName)
if acmeprovider != nil {
if acmeprovider.HTTPChallenge != nil && acmeprovider.HTTPChallenge.EntryPoint == entryPointName {
internalRouter.AddRouter(acmeprovider)
}
// TLS ALPN 01
if acmeprovider.HTTPChallenge == nil && acmeprovider.DNSChallenge == nil && acmeprovider.TLSChallenge != nil {
entryPoint.TLSALPNGetter = acmeprovider.GetTLSALPNCertificate
}
if acmeprovider.EntryPoint == entryPointName && acmeprovider.OnDemand {
entryPoint.OnDemandListener = acmeprovider.ListenRequest
}
entryPoint.CertificateStore = traefiktls.NewCertificateStore()
acmeprovider.SetCertificateStore(entryPoint.CertificateStore)
}
entryPoint.InternalRouter = internalRouter
entryPoints[entryPointName] = entryPoint
}
svr := server.NewServer(*globalConfiguration, providerAggregator, entryPoints)
if acmeprovider != nil && acmeprovider.OnHostRule {
acmeprovider.SetConfigListenerChan(make(chan types.Configuration))
svr.AddListener(acmeprovider.ListenConfiguration)
}
ctx := cmd.ContextWithSignal(context.Background())
if globalConfiguration.Ping != nil {
globalConfiguration.Ping.WithContext(ctx)
}
svr.StartWithContext(ctx)
defer svr.Close()

View File

@@ -11,6 +11,8 @@ import (
"github.com/containous/traefik/api"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/middlewares/tracing/jaeger"
"github.com/containous/traefik/middlewares/tracing/zipkin"
"github.com/containous/traefik/ping"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/boltdb"
@@ -48,24 +50,27 @@ const (
// DefaultGraceTimeout controls how long Traefik serves pending requests
// prior to shutting down.
DefaultGraceTimeout = 10 * time.Second
// DefaultAcmeCAServer is the default ACME API endpoint
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
)
// GlobalConfiguration holds global configuration (with providers, etc.).
// It's populated from the traefik configuration file passed as an argument to the binary.
type GlobalConfiguration struct {
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
GraceTimeOut flaeg.Duration `short:"g" description:"(Deprecated) Duration to give active requests a chance to finish before Traefik stops" export:"true"` // Deprecated
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
AccessLogsFile string `description:"(Deprecated) Access logs file" export:"true"` // Deprecated
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
TraefikLogsFile string `description:"(Deprecated) Traefik logs file. Stdout is used when omitted or empty" export:"true"` // Deprecated
TraefikLog *types.TraefikLog `description:"Traefik log settings" export:"true"`
Tracing *tracing.Tracing `description:"OpenTracing configuration" export:"true"`
LogLevel string `short:"l" description:"Log level" export:"true"`
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
Cluster *types.Cluster `description:"Enable clustering" export:"true"`
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
GraceTimeOut flaeg.Duration `short:"g" description:"(Deprecated) Duration to give active requests a chance to finish before Traefik stops" export:"true"` // Deprecated
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
AccessLogsFile string `description:"(Deprecated) Access logs file" export:"true"` // Deprecated
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
TraefikLogsFile string `description:"(Deprecated) Traefik logs file. Stdout is used when omitted or empty" export:"true"` // Deprecated
TraefikLog *types.TraefikLog `description:"Traefik log settings" export:"true"`
Tracing *tracing.Tracing `description:"OpenTracing configuration" export:"true"`
LogLevel string `short:"l" description:"Log level" export:"true"`
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
Cluster *types.Cluster
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags" export:"true"`
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
DefaultEntryPoints DefaultEntryPoints `description:"Entrypoints to be used by frontends that do not specify any entrypoint" export:"true"`
@@ -78,6 +83,7 @@ type GlobalConfiguration struct {
HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
AllowMinWeightZero bool `description:"Allow weight to take 0 as minimum real value." export:"true"` // Deprecated
Web *WebCompatibility `description:"(Deprecated) Enable Web backend with default settings" export:"true"` // Deprecated
Docker *docker.Provider `description:"Enable Docker backend with default settings" export:"true"`
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
@@ -98,17 +104,18 @@ type GlobalConfiguration struct {
API *api.Handler `description:"Enable api/dashboard" export:"true"`
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
Ping *ping.Handler `description:"Enable ping" export:"true"`
HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
}
// WebCompatibility is a configuration to handle compatibility with deprecated web provider options
type WebCompatibility struct {
Address string `description:"Web administration port" export:"true"`
CertFile string `description:"SSL certificate" export:"true"`
KeyFile string `description:"SSL certificate" export:"true"`
ReadOnly bool `description:"Enable read only API" export:"true"`
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
Path string `description:"Root path for dashboard and API" export:"true"`
Address string `description:"(Deprecated) Web administration port" export:"true"`
CertFile string `description:"(Deprecated) SSL certificate" export:"true"`
KeyFile string `description:"(Deprecated) SSL certificate" export:"true"`
ReadOnly bool `description:"(Deprecated) Enable read only API" export:"true"`
Statistics *types.Statistics `description:"(Deprecated) Enable more detailed statistics" export:"true"`
Metrics *types.Metrics `description:"(Deprecated) Enable a metrics exporter" export:"true"`
Path string `description:"(Deprecated) Root path for dashboard and API" export:"true"`
Auth *types.Auth `export:"true"`
Debug bool `export:"true"`
}
@@ -230,6 +237,15 @@ func (gc *GlobalConfiguration) SetEffectiveConfiguration(configFile string) {
}
}
if gc.Mesos != nil {
if len(gc.Mesos.Filename) != 0 && gc.Mesos.TemplateVersion != 2 {
log.Warn("Template version 1 is deprecated, please use version 2, see TemplateVersion.")
gc.Mesos.TemplateVersion = 1
} else {
gc.Mesos.TemplateVersion = 2
}
}
if gc.Eureka != nil {
if gc.Eureka.Delay != 0 {
log.Warn("Delay has been deprecated -- please use RefreshSeconds")
@@ -237,6 +253,24 @@ func (gc *GlobalConfiguration) SetEffectiveConfiguration(configFile string) {
}
}
if gc.ECS != nil {
if len(gc.ECS.Filename) != 0 && gc.ECS.TemplateVersion != 2 {
log.Warn("Template version 1 is deprecated, please use version 2, see TemplateVersion.")
gc.ECS.TemplateVersion = 1
} else {
gc.ECS.TemplateVersion = 2
}
}
if gc.ConsulCatalog != nil {
if len(gc.ConsulCatalog.Filename) != 0 && gc.ConsulCatalog.TemplateVersion != 2 {
log.Warn("Template version 1 is deprecated, please use version 2, see TemplateVersion.")
gc.ConsulCatalog.TemplateVersion = 1
} else {
gc.ConsulCatalog.TemplateVersion = 2
}
}
if gc.Rancher != nil {
if len(gc.Rancher.Filename) != 0 && gc.Rancher.TemplateVersion != 2 {
log.Warn("Template version 1 is deprecated, please use version 2, see TemplateVersion.")
@@ -274,22 +308,70 @@ func (gc *GlobalConfiguration) SetEffectiveConfiguration(configFile string) {
gc.Web.Path += "/"
}
// Try to fallback to traefik config file in case the file provider is enabled
// but has no file name configured and is not in a directory mode.
if gc.File != nil && len(gc.File.Filename) == 0 && len(gc.File.Directory) == 0 {
if len(configFile) > 0 {
gc.File.Filename = configFile
} else {
log.Errorln("Error using file configuration backend, no filename defined")
}
if gc.File != nil {
gc.File.TraefikFile = configFile
}
gc.initACMEProvider()
gc.initTracing()
}
func (gc *GlobalConfiguration) initTracing() {
if gc.Tracing != nil {
switch gc.Tracing.Backend {
case jaeger.Name:
if gc.Tracing.Jaeger == nil {
gc.Tracing.Jaeger = &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
}
}
if gc.Tracing.Zipkin != nil {
log.Warn("Zipkin configuration will be ignored")
gc.Tracing.Zipkin = nil
}
case zipkin.Name:
if gc.Tracing.Zipkin == nil {
gc.Tracing.Zipkin = &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
}
}
if gc.Tracing.Jaeger != nil {
log.Warn("Jaeger configuration will be ignored")
gc.Tracing.Jaeger = nil
}
default:
log.Warnf("Unknown tracer %q", gc.Tracing.Backend)
return
}
}
}
func (gc *GlobalConfiguration) initACMEProvider() {
if gc.ACME != nil {
// TODO: to remove in the futurs
gc.ACME.CAServer = getSafeACMECAServer(gc.ACME.CAServer)
if gc.ACME.DNSChallenge != nil && gc.ACME.HTTPChallenge != nil {
log.Warn("Unable to use DNS challenge and HTTP challenge at the same time. Fallback to DNS challenge.")
gc.ACME.HTTPChallenge = nil
}
if gc.ACME.DNSChallenge != nil && gc.ACME.TLSChallenge != nil {
log.Warn("Unable to use DNS challenge and TLS challenge at the same time. Fallback to DNS challenge.")
gc.ACME.TLSChallenge = nil
}
if gc.ACME.HTTPChallenge != nil && gc.ACME.TLSChallenge != nil {
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
gc.ACME.HTTPChallenge = nil
}
// TODO: to remove in the future
if len(gc.ACME.StorageFile) > 0 && len(gc.ACME.Storage) == 0 {
log.Warn("ACME.StorageFile is deprecated, use ACME.Storage instead")
gc.ACME.Storage = gc.ACME.StorageFile
@@ -303,25 +385,59 @@ func (gc *GlobalConfiguration) initACMEProvider() {
if gc.ACME.OnDemand {
log.Warn("ACME.OnDemand is deprecated")
}
}
}
// InitACMEProvider create an acme provider from the ACME part of globalConfiguration
func (gc *GlobalConfiguration) InitACMEProvider() *acmeprovider.Provider {
if gc.ACME != nil {
// TODO: Remove when Provider ACME will replace totally ACME
// If provider file, use Provider ACME instead of ACME
if gc.Cluster == nil {
acmeprovider.Get().Configuration = &acmeprovider.Configuration{
provider := &acmeprovider.Provider{}
provider.Configuration = &acmeprovider.Configuration{
KeyType: gc.ACME.KeyType,
OnHostRule: gc.ACME.OnHostRule,
OnDemand: gc.ACME.OnDemand,
Email: gc.ACME.Email,
Storage: gc.ACME.Storage,
HTTPChallenge: gc.ACME.HTTPChallenge,
DNSChallenge: gc.ACME.DNSChallenge,
TLSChallenge: gc.ACME.TLSChallenge,
Domains: gc.ACME.Domains,
ACMELogging: gc.ACME.ACMELogging,
CAServer: gc.ACME.CAServer,
EntryPoint: gc.ACME.EntryPoint,
}
store := acmeprovider.NewLocalStore(provider.Storage)
provider.Store = store
acme.ConvertToNewFormat(provider.Storage)
gc.ACME = nil
return provider
}
}
return nil
}
func getSafeACMECAServer(caServerSrc string) string {
if len(caServerSrc) == 0 {
return DefaultAcmeCAServer
}
if strings.HasPrefix(caServerSrc, "https://acme-v01.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "v01", "v02", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer
}
if strings.HasPrefix(caServerSrc, "https://acme-staging.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "https://acme-staging.api.letsencrypt.org", "https://acme-staging-v02.api.letsencrypt.org", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer
}
return caServerSrc
}
// ValidateConfiguration validate that configuration is coherent
@@ -334,14 +450,6 @@ func (gc *GlobalConfiguration) ValidateConfiguration() {
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", gc.ACME.EntryPoint)
}
}
} else if acmeprovider.IsEnabled() {
if _, ok := gc.EntryPoints[acmeprovider.Get().EntryPoint]; !ok {
log.Fatalf("Unknown entrypoint %q for provider ACME configuration", acmeprovider.Get().EntryPoint)
} else {
if gc.EntryPoints[acmeprovider.Get().EntryPoint].TLS == nil {
log.Fatalf("Entrypoint %q has no TLS configuration for provider ACME configuration", acmeprovider.Get().EntryPoint)
}
}
}
}
@@ -412,3 +520,10 @@ type LifeCycle struct {
RequestAcceptGraceTimeout flaeg.Duration `description:"Duration to keep accepting requests before Traefik initiates the graceful shutdown procedure"`
GraceTimeOut flaeg.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"`
}
// HostResolverConfig contain configuration for CNAME Flattening
type HostResolverConfig struct {
CnameFlattening bool `description:"A flag to enable/disable CNAME flattening" export:"true"`
ResolvConfig string `description:"resolv.conf used for DNS resolving" export:"true"`
ResolvDepth int `description:"The maximal depth of DNS recursive resolving" export:"true"`
}

View File

@@ -5,14 +5,18 @@ import (
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/middlewares/tracing/jaeger"
"github.com/containous/traefik/middlewares/tracing/zipkin"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/file"
"github.com/stretchr/testify/assert"
)
const defaultConfigFile = "traefik.toml"
func TestSetEffectiveConfigurationGraceTimeout(t *testing.T) {
tests := []struct {
testCases := []struct {
desc string
legacyGraceTimeout time.Duration
lifeCycleGraceTimeout time.Duration
@@ -37,10 +41,11 @@ func TestSetEffectiveConfigurationGraceTimeout(t *testing.T) {
},
}
for _, test := range tests {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
GraceTimeOut: flaeg.Duration(test.legacyGraceTimeout),
}
@@ -52,52 +57,161 @@ func TestSetEffectiveConfigurationGraceTimeout(t *testing.T) {
gc.SetEffectiveConfiguration(defaultConfigFile)
gotGraceTimeout := time.Duration(gc.LifeCycle.GraceTimeOut)
if gotGraceTimeout != test.wantGraceTimeout {
t.Fatalf("got effective grace timeout %d, want %d", gotGraceTimeout, test.wantGraceTimeout)
}
assert.Equal(t, test.wantGraceTimeout, time.Duration(gc.LifeCycle.GraceTimeOut))
})
}
}
func TestSetEffectiveConfigurationFileProviderFilename(t *testing.T) {
tests := []struct {
desc string
fileProvider *file.Provider
wantFileProviderFilename string
testCases := []struct {
desc string
fileProvider *file.Provider
wantFileProviderFilename string
wantFileProviderTraefikFile string
}{
{
desc: "no filename for file provider given",
fileProvider: &file.Provider{},
wantFileProviderFilename: defaultConfigFile,
desc: "no filename for file provider given",
fileProvider: &file.Provider{},
wantFileProviderFilename: "",
wantFileProviderTraefikFile: defaultConfigFile,
},
{
desc: "filename for file provider given",
fileProvider: &file.Provider{BaseProvider: provider.BaseProvider{Filename: "other.toml"}},
wantFileProviderFilename: "other.toml",
desc: "filename for file provider given",
fileProvider: &file.Provider{BaseProvider: provider.BaseProvider{Filename: "other.toml"}},
wantFileProviderFilename: "other.toml",
wantFileProviderTraefikFile: defaultConfigFile,
},
{
desc: "directory for file provider given",
fileProvider: &file.Provider{Directory: "/"},
wantFileProviderFilename: "",
desc: "directory for file provider given",
fileProvider: &file.Provider{Directory: "/"},
wantFileProviderFilename: "",
wantFileProviderTraefikFile: defaultConfigFile,
},
}
for _, test := range tests {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
File: test.fileProvider,
}
gc.SetEffectiveConfiguration(defaultConfigFile)
gotFileProviderFilename := gc.File.Filename
if gotFileProviderFilename != test.wantFileProviderFilename {
t.Fatalf("got file provider file name %q, want %q", gotFileProviderFilename, test.wantFileProviderFilename)
}
assert.Equal(t, test.wantFileProviderFilename, gc.File.Filename)
assert.Equal(t, test.wantFileProviderTraefikFile, gc.File.TraefikFile)
})
}
}
func TestSetEffectiveConfigurationTracing(t *testing.T) {
testCases := []struct {
desc string
tracing *tracing.Tracing
expected *tracing.Tracing
}{
{
desc: "no tracing configuration",
tracing: &tracing.Tracing{},
expected: &tracing.Tracing{},
},
{
desc: "tracing bad backend name",
tracing: &tracing.Tracing{
Backend: "powpow",
},
expected: &tracing.Tracing{
Backend: "powpow",
},
},
{
desc: "tracing jaeger backend name",
tracing: &tracing.Tracing{
Backend: "jaeger",
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
},
},
expected: &tracing.Tracing{
Backend: "jaeger",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
},
Zipkin: nil,
},
},
{
desc: "tracing zipkin backend name",
tracing: &tracing.Tracing{
Backend: "zipkin",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
},
},
expected: &tracing.Tracing{
Backend: "zipkin",
Jaeger: nil,
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
},
},
},
{
desc: "tracing zipkin backend name value override",
tracing: &tracing.Tracing{
Backend: "zipkin",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
},
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://powpow:9411/api/v1/spans",
SameSpan: true,
ID128Bit: true,
Debug: true,
},
},
expected: &tracing.Tracing{
Backend: "zipkin",
Jaeger: nil,
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://powpow:9411/api/v1/spans",
SameSpan: true,
ID128Bit: true,
Debug: true,
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
Tracing: test.tracing,
}
gc.SetEffectiveConfiguration(defaultConfigFile)
assert.Equal(t, test.expected, gc.Tracing)
})
}
}

View File

@@ -106,14 +106,16 @@ func makeEntryPointAuth(result map[string]string) *types.Auth {
var basic *types.Basic
if v, ok := result["auth_basic_users"]; ok {
basic = &types.Basic{
Users: strings.Split(v, ","),
Users: strings.Split(v, ","),
RemoveHeader: toBool(result, "auth_basic_removeheader"),
}
}
var digest *types.Digest
if v, ok := result["auth_digest_users"]; ok {
digest = &types.Digest{
Users: strings.Split(v, ","),
Users: strings.Split(v, ","),
RemoveHeader: toBool(result, "auth_digest_removeheader"),
}
}
@@ -135,10 +137,16 @@ func makeEntryPointAuth(result map[string]string) *types.Auth {
}
}
var authResponseHeaders []string
if v, ok := result["auth_forward_authresponseheaders"]; ok {
authResponseHeaders = strings.Split(v, ",")
}
forward = &types.Forward{
Address: address,
TLS: clientTLS,
TrustForwardHeader: toBool(result, "auth_forward_trustforwardheader"),
Address: address,
TLS: clientTLS,
TrustForwardHeader: toBool(result, "auth_forward_trustforwardheader"),
AuthResponseHeaders: authResponseHeaders,
}
}
@@ -224,12 +232,33 @@ func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) {
}
}
if len(result["ca"]) > 0 {
files := strings.Split(result["ca"], ",")
optional := toBool(result, "ca_optional")
configTLS.ClientCA = tls.ClientCA{
Files: files,
Optional: optional,
if configTLS != nil {
if len(result["ca"]) > 0 {
files := strings.Split(result["ca"], ",")
optional := toBool(result, "ca_optional")
configTLS.ClientCA = tls.ClientCA{
Files: files,
Optional: optional,
}
}
if len(result["tls_minversion"]) > 0 {
configTLS.MinVersion = result["tls_minversion"]
}
if len(result["tls_ciphersuites"]) > 0 {
configTLS.CipherSuites = strings.Split(result["tls_ciphersuites"], ",")
}
if len(result["tls_snistrict"]) > 0 {
configTLS.SniStrict = toBool(result, "tls_snistrict")
}
if len(result["tls_defaultcertificate_cert"]) > 0 && len(result["tls_defaultcertificate_key"]) > 0 {
configTLS.DefaultCertificate = &tls.Certificate{
CertFile: tls.FileOrContent(result["tls_defaultcertificate_cert"]),
KeyFile: tls.FileOrContent(result["tls_defaultcertificate_key"]),
}
}
}

View File

@@ -21,6 +21,8 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"Address::8000 " +
"TLS:goo,gii " +
"TLS " +
"TLS.MinVersion:VersionTLS11 " +
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"CA:car " +
"CA.Optional:true " +
"Redirect.EntryPoint:https " +
@@ -31,9 +33,12 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
"Auth.Basic.RemoveHeader:true " +
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
"Auth.Digest.RemoveHeader:true " +
"Auth.HeaderField:X-WebAuth-User " +
"Auth.Forward.Address:https://authserver.com/auth " +
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
"Auth.Forward.TrustForwardHeader:true " +
"Auth.Forward.TLS.CA:path/to/local.crt " +
"Auth.Forward.TLS.CAOptional:true " +
@@ -46,8 +51,11 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
expectedResult: map[string]string{
"address": ":8000",
"auth_basic_users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
"auth_basic_removeheader": "true",
"auth_digest_users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
"auth_digest_removeheader": "true",
"auth_forward_address": "https://authserver.com/auth",
"auth_forward_authresponseheaders": "X-Auth,X-Test,X-Secret",
"auth_forward_tls_ca": "path/to/local.crt",
"auth_forward_tls_caoptional": "true",
"auth_forward_tls_cert": "path/to/foo.cert",
@@ -67,6 +75,8 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"redirect_replacement": "http://mydomain/$1",
"tls": "goo,gii",
"tls_acme": "TLS",
"tls_ciphersuites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"tls_minversion": "VersionTLS11",
"whitelistsourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
"whitelist_usexforwardedfor": "true",
@@ -170,8 +180,10 @@ func TestEntryPoints_Set(t *testing.T) {
name: "all parameters camelcase",
expression: "Name:foo " +
"Address::8000 " +
"TLS:goo,gii " +
"TLS:goo,gii;foo,fii " +
"TLS " +
"TLS.MinVersion:VersionTLS11 " +
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"CA:car " +
"CA.Optional:true " +
"Redirect.EntryPoint:https " +
@@ -182,9 +194,12 @@ func TestEntryPoints_Set(t *testing.T) {
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
"Auth.Basic.RemoveHeader:true " +
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
"Auth.Digest.RemoveHeader:true " +
"Auth.HeaderField:X-WebAuth-User " +
"Auth.Forward.Address:https://authserver.com/auth " +
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
"Auth.Forward.TrustForwardHeader:true " +
"Auth.Forward.TLS.CA:path/to/local.crt " +
"Auth.Forward.TLS.CAOptional:true " +
@@ -198,11 +213,17 @@ func TestEntryPoints_Set(t *testing.T) {
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{
Files: []string{"car"},
@@ -217,19 +238,22 @@ func TestEntryPoints_Set(t *testing.T) {
},
Auth: &types.Auth{
Basic: &types.Basic{
RemoveHeader: true,
Users: types.Users{
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
},
},
Digest: &types.Digest{
RemoveHeader: true,
Users: types.Users{
"test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
},
},
Forward: &types.Forward{
Address: "https://authserver.com/auth",
Address: "https://authserver.com/auth",
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
TLS: &types.ClientTLS{
CA: "path/to/local.crt",
CAOptional: true,
@@ -272,8 +296,10 @@ func TestEntryPoints_Set(t *testing.T) {
name: "all parameters lowercase",
expression: "Name:foo " +
"address::8000 " +
"tls:goo,gii " +
"tls:goo,gii;foo,fii " +
"tls " +
"tls.minversion:VersionTLS11 " +
"tls.ciphersuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"ca:car " +
"ca.Optional:true " +
"redirect.entryPoint:https " +
@@ -288,6 +314,7 @@ func TestEntryPoints_Set(t *testing.T) {
"auth.digest.users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
"auth.headerField:X-WebAuth-User " +
"auth.forward.address:https://authserver.com/auth " +
"auth.forward.authResponseHeaders:X-Auth,X-Test,X-Secret " +
"auth.forward.trustForwardHeader:true " +
"auth.forward.tls.ca:path/to/local.crt " +
"auth.forward.tls.caOptional:true " +
@@ -298,11 +325,17 @@ func TestEntryPoints_Set(t *testing.T) {
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{
Files: []string{"car"},
@@ -329,7 +362,8 @@ func TestEntryPoints_Set(t *testing.T) {
},
},
Forward: &types.Forward{
Address: "https://authserver.com/auth",
Address: "https://authserver.com/auth",
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
TLS: &types.ClientTLS{
CA: "path/to/local.crt",
CAOptional: true,

View File

@@ -2,94 +2,110 @@ package configuration
import (
"encoding/json"
"reflect"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
)
type providerAggregator struct {
providers []provider.Provider
// ProviderAggregator aggregate providers
type ProviderAggregator struct {
providers []provider.Provider
constraints types.Constraints
}
// NewProviderAggregator return an aggregate of all the providers configured in GlobalConfiguration
func NewProviderAggregator(gc *GlobalConfiguration) provider.Provider {
provider := providerAggregator{}
func NewProviderAggregator(gc *GlobalConfiguration) ProviderAggregator {
provider := ProviderAggregator{
constraints: gc.Constraints,
}
if gc.Docker != nil {
provider.providers = append(provider.providers, gc.Docker)
provider.quietAddProvider(gc.Docker)
}
if gc.Marathon != nil {
provider.providers = append(provider.providers, gc.Marathon)
provider.quietAddProvider(gc.Marathon)
}
if gc.File != nil {
provider.providers = append(provider.providers, gc.File)
provider.quietAddProvider(gc.File)
}
if gc.Rest != nil {
provider.providers = append(provider.providers, gc.Rest)
provider.quietAddProvider(gc.Rest)
}
if gc.Consul != nil {
provider.providers = append(provider.providers, gc.Consul)
provider.quietAddProvider(gc.Consul)
}
if gc.ConsulCatalog != nil {
provider.providers = append(provider.providers, gc.ConsulCatalog)
provider.quietAddProvider(gc.ConsulCatalog)
}
if gc.Etcd != nil {
provider.providers = append(provider.providers, gc.Etcd)
provider.quietAddProvider(gc.Etcd)
}
if gc.Zookeeper != nil {
provider.providers = append(provider.providers, gc.Zookeeper)
provider.quietAddProvider(gc.Zookeeper)
}
if gc.Boltdb != nil {
provider.providers = append(provider.providers, gc.Boltdb)
provider.quietAddProvider(gc.Boltdb)
}
if gc.Kubernetes != nil {
provider.providers = append(provider.providers, gc.Kubernetes)
provider.quietAddProvider(gc.Kubernetes)
}
if gc.Mesos != nil {
provider.providers = append(provider.providers, gc.Mesos)
provider.quietAddProvider(gc.Mesos)
}
if gc.Eureka != nil {
provider.providers = append(provider.providers, gc.Eureka)
provider.quietAddProvider(gc.Eureka)
}
if gc.ECS != nil {
provider.providers = append(provider.providers, gc.ECS)
provider.quietAddProvider(gc.ECS)
}
if gc.Rancher != nil {
provider.providers = append(provider.providers, gc.Rancher)
provider.quietAddProvider(gc.Rancher)
}
if gc.DynamoDB != nil {
provider.providers = append(provider.providers, gc.DynamoDB)
provider.quietAddProvider(gc.DynamoDB)
}
if gc.ServiceFabric != nil {
provider.providers = append(provider.providers, gc.ServiceFabric)
}
if acmeprovider.IsEnabled() {
provider.providers = append(provider.providers, acmeprovider.Get())
acme.ConvertToNewFormat(acmeprovider.Get().Storage)
}
if len(provider.providers) == 1 {
return provider.providers[0]
provider.quietAddProvider(gc.ServiceFabric)
}
return provider
}
func (p providerAggregator) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
err := p.AddProvider(provider)
if err != nil {
log.Errorf("Error initializing provider %T: %v", provider, err)
}
}
// AddProvider add a provider in the providers map
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
err := provider.Init(p.constraints)
if err != nil {
return err
}
p.providers = append(p.providers, provider)
return nil
}
// Init the provider
func (p ProviderAggregator) Init(_ types.Constraints) error {
return nil
}
// Provide call the provide method of every providers
func (p ProviderAggregator) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
for _, p := range p.providers {
providerType := reflect.TypeOf(p)
jsonConf, err := json.Marshal(p)
if err != nil {
log.Debugf("Unable to marshal provider conf %v with error: %v", providerType, err)
log.Debugf("Unable to marshal provider conf %T with error: %v", p, err)
}
log.Infof("Starting provider %v %s", providerType, jsonConf)
log.Infof("Starting provider %T %s", p, jsonConf)
currentProvider := p
safe.Go(func() {
err := currentProvider.Provide(configurationChan, pool, constraints)
err := currentProvider.Provide(configurationChan, pool)
if err != nil {
log.Errorf("Error starting provider %v: %s", providerType, err)
log.Errorf("Error starting provider %T: %v", p, err)
}
})
}

View File

@@ -0,0 +1,132 @@
package router
import (
"github.com/containous/mux"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/log"
"github.com/containous/traefik/metrics"
"github.com/containous/traefik/middlewares"
mauth "github.com/containous/traefik/middlewares/auth"
"github.com/containous/traefik/types"
"github.com/urfave/negroni"
)
// NewInternalRouterAggregator Create a new internalRouterAggregator
func NewInternalRouterAggregator(globalConfiguration configuration.GlobalConfiguration, entryPointName string) *InternalRouterAggregator {
var serverMiddlewares []negroni.Handler
if globalConfiguration.EntryPoints[entryPointName].WhiteList != nil {
ipWhitelistMiddleware, err := middlewares.NewIPWhiteLister(
globalConfiguration.EntryPoints[entryPointName].WhiteList.SourceRange,
globalConfiguration.EntryPoints[entryPointName].WhiteList.UseXForwardedFor)
if err != nil {
log.Fatalf("Error creating whitelist middleware: %s", err)
}
if ipWhitelistMiddleware != nil {
serverMiddlewares = append(serverMiddlewares, ipWhitelistMiddleware)
}
}
if globalConfiguration.EntryPoints[entryPointName].Auth != nil {
authMiddleware, err := mauth.NewAuthenticator(globalConfiguration.EntryPoints[entryPointName].Auth, nil)
if err != nil {
log.Fatalf("Error creating authenticator middleware: %s", err)
}
serverMiddlewares = append(serverMiddlewares, authMiddleware)
}
router := InternalRouterAggregator{}
routerWithPrefix := InternalRouterAggregator{}
routerWithPrefixAndMiddleware := InternalRouterAggregator{}
if globalConfiguration.Metrics != nil && globalConfiguration.Metrics.Prometheus != nil && globalConfiguration.Metrics.Prometheus.EntryPoint == entryPointName {
routerWithPrefixAndMiddleware.AddRouter(metrics.PrometheusHandler{})
}
if globalConfiguration.Rest != nil && globalConfiguration.Rest.EntryPoint == entryPointName {
routerWithPrefixAndMiddleware.AddRouter(globalConfiguration.Rest)
}
if globalConfiguration.API != nil && globalConfiguration.API.EntryPoint == entryPointName {
routerWithPrefixAndMiddleware.AddRouter(globalConfiguration.API)
}
if globalConfiguration.Ping != nil && globalConfiguration.Ping.EntryPoint == entryPointName {
routerWithPrefix.AddRouter(globalConfiguration.Ping)
}
if globalConfiguration.ACME != nil && globalConfiguration.ACME.HTTPChallenge != nil && globalConfiguration.ACME.HTTPChallenge.EntryPoint == entryPointName {
router.AddRouter(globalConfiguration.ACME)
}
realRouterWithMiddleware := WithMiddleware{router: &routerWithPrefixAndMiddleware, routerMiddlewares: serverMiddlewares}
if globalConfiguration.Web != nil && globalConfiguration.Web.Path != "" {
router.AddRouter(&WithPrefix{PathPrefix: globalConfiguration.Web.Path, Router: &routerWithPrefix})
router.AddRouter(&WithPrefix{PathPrefix: globalConfiguration.Web.Path, Router: &realRouterWithMiddleware})
} else {
router.AddRouter(&routerWithPrefix)
router.AddRouter(&realRouterWithMiddleware)
}
return &router
}
// WithMiddleware router with internal middleware
type WithMiddleware struct {
router types.InternalRouter
routerMiddlewares []negroni.Handler
}
// AddRoutes Add routes to the router
func (wm *WithMiddleware) AddRoutes(systemRouter *mux.Router) {
realRouter := systemRouter.PathPrefix("/").Subrouter()
wm.router.AddRoutes(realRouter)
if len(wm.routerMiddlewares) > 0 {
realRouter.Walk(wrapRoute(wm.routerMiddlewares))
}
}
// WithPrefix router which add a prefix
type WithPrefix struct {
Router types.InternalRouter
PathPrefix string
}
// AddRoutes Add routes to the router
func (wp *WithPrefix) AddRoutes(systemRouter *mux.Router) {
realRouter := systemRouter.PathPrefix("/").Subrouter()
if wp.PathPrefix != "" {
realRouter = systemRouter.PathPrefix(wp.PathPrefix).Subrouter()
realRouter.StrictSlash(true)
realRouter.SkipClean(true)
}
wp.Router.AddRoutes(realRouter)
}
// InternalRouterAggregator InternalRouter that aggregate other internalRouter
type InternalRouterAggregator struct {
internalRouters []types.InternalRouter
}
// AddRouter add a router in the aggregator
func (r *InternalRouterAggregator) AddRouter(router types.InternalRouter) {
r.internalRouters = append(r.internalRouters, router)
}
// AddRoutes Add routes to the router
func (r *InternalRouterAggregator) AddRoutes(systemRouter *mux.Router) {
for _, router := range r.internalRouters {
router.AddRoutes(systemRouter)
}
}
// wrapRoute with middlewares
func wrapRoute(middlewares []negroni.Handler) func(*mux.Route, *mux.Router, []*mux.Route) error {
return func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
middles := append(middlewares, negroni.Wrap(route.GetHandler()))
route.Handler(negroni.New(middles...))
return nil
}
}

View File

@@ -0,0 +1,346 @@
package router
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/mux"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/api"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/ping"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
"github.com/urfave/negroni"
)
func TestNewInternalRouterAggregatorWithWebPath(t *testing.T) {
currentConfiguration := &safe.Safe{}
currentConfiguration.Set(types.Configurations{})
globalConfiguration := configuration.GlobalConfiguration{
Web: &configuration.WebCompatibility{
Path: "/prefix",
},
API: &api.Handler{
EntryPoint: "traefik",
CurrentConfigurations: currentConfiguration,
},
Ping: &ping.Handler{
EntryPoint: "traefik",
},
ACME: &acme.ACME{
HTTPChallenge: &acmeprovider.HTTPChallenge{
EntryPoint: "traefik",
},
},
EntryPoints: configuration.EntryPoints{
"traefik": &configuration.EntryPoint{},
},
}
testCases := []struct {
desc string
testedURL string
expectedStatusCode int
}{
{
desc: "Ping without prefix",
testedURL: "/ping",
expectedStatusCode: 502,
},
{
desc: "Ping with prefix",
testedURL: "/prefix/ping",
expectedStatusCode: 200,
},
{
desc: "acme without prefix",
testedURL: "/.well-known/acme-challenge/token",
expectedStatusCode: 404,
},
{
desc: "api without prefix",
testedURL: "/api",
expectedStatusCode: 502,
},
{
desc: "api with prefix",
testedURL: "/prefix/api",
expectedStatusCode: 200,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
router := NewInternalRouterAggregator(globalConfiguration, "traefik")
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
internalMuxRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
})
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, test.testedURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
assert.Equal(t, test.expectedStatusCode, recorder.Code)
})
}
}
func TestNewInternalRouterAggregatorWithAuth(t *testing.T) {
currentConfiguration := &safe.Safe{}
currentConfiguration.Set(types.Configurations{})
globalConfiguration := configuration.GlobalConfiguration{
API: &api.Handler{
EntryPoint: "traefik",
CurrentConfigurations: currentConfiguration,
},
Ping: &ping.Handler{
EntryPoint: "traefik",
},
ACME: &acme.ACME{
HTTPChallenge: &acmeprovider.HTTPChallenge{
EntryPoint: "traefik",
},
},
EntryPoints: configuration.EntryPoints{
"traefik": &configuration.EntryPoint{
Auth: &types.Auth{
Basic: &types.Basic{
Users: types.Users{"test:test"},
},
},
},
},
}
testCases := []struct {
desc string
testedURL string
expectedStatusCode int
}{
{
desc: "Wrong url",
testedURL: "/wrong",
expectedStatusCode: 502,
},
{
desc: "Ping without auth",
testedURL: "/ping",
expectedStatusCode: 200,
},
{
desc: "acme without auth",
testedURL: "/.well-known/acme-challenge/token",
expectedStatusCode: 404,
},
{
desc: "api with auth",
testedURL: "/api",
expectedStatusCode: 401,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
router := NewInternalRouterAggregator(globalConfiguration, "traefik")
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
internalMuxRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
})
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, test.testedURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
assert.Equal(t, test.expectedStatusCode, recorder.Code)
})
}
}
func TestNewInternalRouterAggregatorWithAuthAndPrefix(t *testing.T) {
currentConfiguration := &safe.Safe{}
currentConfiguration.Set(types.Configurations{})
globalConfiguration := configuration.GlobalConfiguration{
Web: &configuration.WebCompatibility{
Path: "/prefix",
},
API: &api.Handler{
EntryPoint: "traefik",
CurrentConfigurations: currentConfiguration,
},
Ping: &ping.Handler{
EntryPoint: "traefik",
},
ACME: &acme.ACME{
HTTPChallenge: &acmeprovider.HTTPChallenge{
EntryPoint: "traefik",
},
},
EntryPoints: configuration.EntryPoints{
"traefik": &configuration.EntryPoint{
Auth: &types.Auth{
Basic: &types.Basic{
Users: types.Users{"test:test"},
},
},
},
},
}
testCases := []struct {
desc string
testedURL string
expectedStatusCode int
}{
{
desc: "Ping without prefix",
testedURL: "/ping",
expectedStatusCode: 502,
},
{
desc: "Ping without auth and with prefix",
testedURL: "/prefix/ping",
expectedStatusCode: 200,
},
{
desc: "acme without auth and without prefix",
testedURL: "/.well-known/acme-challenge/token",
expectedStatusCode: 404,
},
{
desc: "api with auth and prefix",
testedURL: "/prefix/api",
expectedStatusCode: 401,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
router := NewInternalRouterAggregator(globalConfiguration, "traefik")
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
internalMuxRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
})
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, test.testedURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
assert.Equal(t, test.expectedStatusCode, recorder.Code)
})
}
}
type MockInternalRouterFunc func(systemRouter *mux.Router)
func (m MockInternalRouterFunc) AddRoutes(systemRouter *mux.Router) {
m(systemRouter)
}
func TestWithMiddleware(t *testing.T) {
router := WithMiddleware{
router: MockInternalRouterFunc(func(systemRouter *mux.Router) {
systemRouter.Handle("/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("router"))
}))
}),
routerMiddlewares: []negroni.Handler{
negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
rw.Write([]byte("before middleware1|"))
next.ServeHTTP(rw, r)
rw.Write([]byte("|after middleware1"))
}),
negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
rw.Write([]byte("before middleware2|"))
next.ServeHTTP(rw, r)
rw.Write([]byte("|after middleware2"))
}),
},
}
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, "/test", nil)
internalMuxRouter.ServeHTTP(recorder, request)
obtained := recorder.Body.String()
assert.Equal(t, "before middleware1|before middleware2|router|after middleware2|after middleware1", obtained)
}
func TestWithPrefix(t *testing.T) {
testCases := []struct {
desc string
prefix string
testedURL string
expectedStatusCode int
}{
{
desc: "No prefix",
testedURL: "/test",
expectedStatusCode: 200,
},
{
desc: "With prefix and wrong url",
prefix: "/prefix",
testedURL: "/test",
expectedStatusCode: 404,
},
{
desc: "With prefix",
prefix: "/prefix",
testedURL: "/prefix/test",
expectedStatusCode: 200,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
router := WithPrefix{
Router: MockInternalRouterFunc(func(systemRouter *mux.Router) {
systemRouter.Handle("/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
}),
PathPrefix: test.prefix,
}
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, test.testedURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
assert.Equal(t, test.expectedStatusCode, recorder.Code)
})
}
}

File diff suppressed because it is too large Load Diff

1055
contrib/grafana/traefik.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,7 @@ ${USAGE}" >&2
bad_acme() {
echo "
There was a problem parsing your acme.json file. $1
There was a problem parsing your acme.json file.
${USAGE}" >&2
exit 2

View File

@@ -1,11 +1,10 @@
FROM alpine
FROM alpine:3.7
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.local/bin
COPY requirements.txt /mkdocs/
WORKDIR /mkdocs
VOLUME /mkdocs
RUN apk --update upgrade \
&& apk --no-cache --no-progress add py-pip \
&& rm -rf /var/cache/apk/* \
&& pip install --user -r requirements.txt
RUN apk --no-cache --no-progress add py-pip \
&& pip install --user -r requirements.txt

View File

@@ -170,7 +170,7 @@ Here is an example of frontends definition:
- Three frontends are defined: `frontend1`, `frontend2` and `frontend3`
- `frontend1` will forward the traffic to the `backend2` if the rule `Host:test.localhost,test2.localhost` is matched
- `frontend2` will forward the traffic to the `backend1` if the rule `Host:localhost,{subdomain:[a-z]+}.localhost` is matched (forwarding client `Host` header to the backend)
- `frontend2` will forward the traffic to the `backend1` if the rule `HostRegexp:localhost,{subdomain:[a-z]+}.localhost` is matched (forwarding client `Host` header to the backend)
- `frontend3` will forward the traffic to the `backend2` if the rules `Host:test3.localhost` **AND** `Path:/test` are matched
#### Combining multiple rules
@@ -262,7 +262,7 @@ This allows for setting headers such as `X-Script-Name` to be added to the reque
!!! warning
If the custom header name is the same as one header name of the request or response, it will be replaced.
In this example, all matches to the path `/cheese` will have the `X-Script-Name` header added to the proxied request, and the `X-Custom-Response-Header` added to the response.
In this example, all matches to the path `/cheese` will have the `X-Script-Name` header added to the proxied request and the `X-Custom-Response-Header` header added to the response.
```toml
[frontends]
@@ -276,7 +276,7 @@ In this example, all matches to the path `/cheese` will have the `X-Script-Name`
rule = "PathPrefixStrip:/cheese"
```
In this second example, all matches to the path `/cheese` will have the `X-Script-Name` header added to the proxied request, the `X-Custom-Request-Header` removed to the request and the `X-Custom-Response-Header` removed to the response.
In this second example, all matches to the path `/cheese` will have the `X-Script-Name` header added to the proxied request, the `X-Custom-Request-Header` header removed from the request, and the `X-Custom-Response-Header` header removed from the response.
```toml
[frontends]
@@ -323,12 +323,55 @@ In this example, traffic routed through the first frontend will have the `X-Fram
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
#### Servers
Servers are simply defined using a `url`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
!!! note
Paths in `url` are ignored. Use `Modifier` to specify paths instead.
Here is an example of backends and servers definition:
```toml
[backends]
[backends.backend1]
# ...
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
[backends.backend2]
# ...
[backends.backend2.servers.server1]
url = "https://172.17.0.4:443"
weight = 1
[backends.backend2.servers.server2]
url = "https://172.17.0.5:443"
weight = 2
[backends.backend3]
# ...
[backends.backend3.servers.server1]
url = "h2c://172.17.0.6:80"
weight = 1
```
- Two backends are defined: `backend1` and `backend2`
- `backend1` will forward the traffic to two servers: `172.17.0.2:80` with weight `10` and `172.17.0.3:80` with weight `1`.
- `backend2` will forward the traffic to two servers: `172.17.0.4:443` with weight `1` and `172.17.0.5:443` with weight `2` both using TLS.
- `backend3` will forward the traffic to: `172.17.0.6:80` with weight `1` using HTTP2 without TLS.
#### Load-balancing
Various methods of load-balancing are supported:
- `wrr`: Weighted Round Robin.
- `drr`: Dynamic Round Robin: increases weights on servers that perform better than others.
It also rolls back to original weights if the servers have changed.
#### Circuit breakers
A circuit breaker can also be applied to a backend, preventing high loads on failing servers.
Initial state is Standby. CB observes the statistics and does not modify the request.
In case the condition matches, CB enters Tripped state, where it responds with predefined code or redirects to another frontend.
@@ -346,6 +389,26 @@ For example:
- `LatencyAtQuantileMS(50.0) > 50`: watch latency at quantile in milliseconds.
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`: ratio of response codes in ranges [500-600) and [0-600).
Here is an example of backends and servers definition:
```toml
[backends]
[backends.backend1]
[backends.backend1.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
```
- `backend1` will forward the traffic to two servers: `http://172.17.0.2:80"` with weight `10` and `http://172.17.0.3:80` with weight `1` using default `wrr` load-balancing strategy.
- a circuit breaker is added on `backend1` using the expression `NetworkErrorRatio() > 0.5`: watch error ratio over 10 second sliding window
#### Maximum connections
To proactively prevent backends from being overwhelmed with high load, a maximum connection limit can also be applied to each backend.
Maximum connections can be configured by specifying an integer value for `maxconn.amount` and `maxconn.extractorfunc` which is a strategy used to determine how to categorize requests in order to evaluate the maximum connections.
@@ -357,13 +420,14 @@ For example:
[backends.backend1.maxconn]
amount = 10
extractorfunc = "request.host"
# ...
```
- `backend1` will return `HTTP code 429 Too Many Requests` if there are already 10 requests in progress for the same Host header.
- Another possible value for `extractorfunc` is `client.ip` which will categorize requests based on client source ip.
- Lastly `extractorfunc` can take the value of `request.header.ANY_HEADER` which will categorize requests based on `ANY_HEADER` that you provide.
### Sticky sessions
#### Sticky sessions
Sticky sessions are supported with both load balancers.
When sticky sessions are enabled, a cookie is set on the initial request.
@@ -371,7 +435,6 @@ The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`).
On subsequent requests, the client will be directed to the backend stored in the cookie if it is still healthy.
If not, a new backend will be assigned.
```toml
[backends]
[backends.backend1]
@@ -395,15 +458,14 @@ The deprecated way:
sticky = true
```
### Health Check
#### Health Check
A health check can be configured in order to remove a backend from LB rotation as long as it keeps returning HTTP status codes other than `200 OK` to HTTP GET requests periodically carried out by Traefik.
The check is defined by a pathappended to the backend URL and an interval (given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration)) specifying how often the health check should be executed (the default being 30 seconds).
A health check can be configured in order to remove a backend from LB rotation as long as it keeps returning HTTP status codes other than `2xx` or `3xx` to HTTP GET requests periodically carried out by Traefik.
The check is defined by a path appended to the backend URL and an interval (given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration)) specifying how often the health check should be executed (the default being 30 seconds).
Each backend must respond to the health check within 5 seconds.
By default, the port of the backend server is used, however, this may be overridden.
A recovering backend returning 200 OK responses again is being returned to the
LB rotation pool.
A recovering backend returning `2xx` or `3xx` responses again is being returned to the LB rotation pool.
For example:
```toml
@@ -414,7 +476,7 @@ For example:
interval = "10s"
```
To use a different port for the healthcheck:
To use a different port for the health check:
```toml
[backends]
[backends.backend1]
@@ -424,42 +486,30 @@ To use a different port for the healthcheck:
port = 8080
```
### Servers
Servers are simply defined using a `url`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
!!! note
Paths in `url` are ignored. Use `Modifier` to specify paths instead.
Here is an example of backends and servers definition:
To use a different scheme for the health check:
```toml
[backends]
[backends.backend1]
[backends.backend1.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
[backends.backend2]
[backends.backend2.LoadBalancer]
method = "drr"
[backends.backend2.servers.server1]
url = "http://172.17.0.4:80"
weight = 1
[backends.backend2.servers.server2]
url = "http://172.17.0.5:80"
weight = 2
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
scheme = "http"
```
- Two backends are defined: `backend1` and `backend2`
- `backend1` will forward the traffic to two servers: `http://172.17.0.2:80"` with weight `10` and `http://172.17.0.3:80` with weight `1` using default `wrr` load-balancing strategy.
- `backend2` will forward the traffic to two servers: `http://172.17.0.4:80"` with weight `1` and `http://172.17.0.5:80` with weight `2` using `drr` load-balancing strategy.
- a circuit breaker is added on `backend1` using the expression `NetworkErrorRatio() > 0.5`: watch error ratio over 10 second sliding window
Additional http headers and hostname to health check request can be specified, for instance:
```toml
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
hostname = "myhost.com"
port = 8080
[backends.backend1.healthcheck.headers]
My-Custom-Header = "foo"
My-Header = "bar"
```
## Configuration
@@ -645,18 +695,18 @@ Once a day (the first call begins 10 minutes after the start of Træfik), we col
swarmMode = true
[Docker.TLS]
CA = "dockerCA"
Cert = "dockerCert"
Key = "dockerKey"
InsecureSkipVerify = true
ca = "dockerCA"
cert = "dockerCert"
key = "dockerKey"
insecureSkipVerify = true
[ECS]
Domain = "foo.bar"
ExposedByDefault = true
Clusters = ["foo-bar"]
Region = "us-west-2"
AccessKeyID = "AccessKeyID"
SecretAccessKey = "SecretAccessKey"
domain = "foo.bar"
exposedByDefault = true
clusters = ["foo-bar"]
region = "us-west-2"
accessKeyID = "AccessKeyID"
secretAccessKey = "SecretAccessKey"
```
- Obfuscated and anonymous configuration:
@@ -669,24 +719,24 @@ Once a day (the first call begins 10 minutes after the start of Træfik), we col
[api]
[Docker]
Endpoint = "xxxx"
Domain = "xxxx"
ExposedByDefault = true
SwarmMode = true
endpoint = "xxxx"
domain = "xxxx"
exposedByDefault = true
swarmMode = true
[Docker.TLS]
CA = "xxxx"
Cert = "xxxx"
Key = "xxxx"
InsecureSkipVerify = false
ca = "xxxx"
cert = "xxxx"
key = "xxxx"
insecureSkipVerify = false
[ECS]
Domain = "xxxx"
ExposedByDefault = true
Clusters = []
Region = "us-west-2"
AccessKeyID = "xxxx"
SecretAccessKey = "xxxx"
domain = "xxxx"
exposedByDefault = true
clusters = []
region = "us-west-2"
accessKeyID = "xxxx"
secretAccessKey = "xxxx"
```
### Show me the code !

View File

@@ -118,7 +118,7 @@ server {
Here is the `traefik.toml` file used:
```toml
MaxIdleConnsPerHost = 100000
maxIdleConnsPerHost = 100000
defaultEntryPoints = ["http"]
[entryPoints]

View File

@@ -1,6 +1,6 @@
# ACME (Let's Encrypt) configuration
# ACME (Let's Encrypt) Configuration
See also [Let's Encrypt examples](/user-guide/examples/#lets-encrypt-support) and [Docker & Let's Encrypt user guide](/user-guide/docker-and-lets-encrypt).
See [Let's Encrypt examples](/user-guide/examples/#lets-encrypt-support) and [Docker & Let's Encrypt user guide](/user-guide/docker-and-lets-encrypt) as well.
## Configuration
@@ -63,14 +63,21 @@ entryPoint = "https"
#
# acmeLogging = true
# Enable on demand certificate generation.
# If true, override certificates in key-value store when using storeconfig.
#
# Optional (Deprecated)
# Optional
# Default: false
#
# overrideCertificates = true
# Deprecated. Enable on demand certificate generation.
#
# Optional
# Default: false
#
# onDemand = true
# Enable certificate generation on frontends Host rules.
# Enable certificate generation on frontends host rules.
#
# Optional
# Default: false
@@ -78,14 +85,23 @@ entryPoint = "https"
# onHostRule = true
# CA server to use.
# - Uncomment the line to run on the staging let's encrypt server.
# - Leave comment to go to prod.
# Uncomment the line to use Let's Encrypt's staging server,
# leave commented to go to prod.
#
# Optional
# Default: "https://acme-v02.api.letsencrypt.org/directory"
#
# caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
# KeyType to use.
#
# Optional
# Default: "RSA4096"
#
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
#
# KeyType = "RSA4096"
# Domains list.
# Only domains defined here can generate wildcard certificates.
#
@@ -94,15 +110,13 @@ entryPoint = "https"
# sans = ["test1.local1.com", "test2.local1.com"]
# [[acme.domains]]
# main = "local2.com"
# sans = ["test1.local2.com", "test2.local2.com"]
# [[acme.domains]]
# main = "local3.com"
# [[acme.domains]]
# main = "local4.com"
# main = "*.local3.com"
# sans = ["local3.com", "test1.test1.local3.com"]
# Use a HTTP-01 acme challenge.
# Use a HTTP-01 ACME challenge.
#
# Optional but recommend
# Optional (but recommended)
#
[acme.httpChallenge]
@@ -112,21 +126,21 @@ entryPoint = "https"
#
entryPoint = "http"
# Use a DNS-01/DNS-02 acme challenge rather than HTTP-01 challenge.
# Note : Mandatory for wildcard certificates generation.
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
# Note: mandatory for wildcard certificate generation.
#
# Optional
#
# [acme.dnsChallenge]
# Provider used.
# DNS provider used.
#
# Required
#
# provider = "digitalocean"
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
# If delayBeforeCheck is greater than zero, avoid this & instead just wait so many seconds.
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
# Useful if internal networks block external DNS queries.
#
# Optional
@@ -135,98 +149,37 @@ entryPoint = "https"
# delayBeforeCheck = 0
```
!!! note
If `HTTP-01` challenge is used, `acme.httpChallenge.entryPoint` has to be defined and reachable by Let's Encrypt through the port 80.
These are Let's Encrypt limitations as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
### `caServer`
!!! note
Wildcard certificates can be generated only if `acme.dnsChallenge`
option is enable.
The CA server to use.
### Let's Encrypt downtime
Let's Encrypt functionality will be limited until Træfik is restarted.
If Let's Encrypt is not reachable, these certificates will be used :
- ACME certificates already generated before downtime
- Expired ACME certificates
- Provided certificates
!!! note
Default Træfik certificate will be used instead of ACME certificates for new (sub)domains (which need Let's Encrypt challenge).
### `storage`
This example shows the usage of Let's Encrypt's staging server:
```toml
[acme]
# ...
storage = "acme.json"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
# ...
```
The `storage` option sets where are stored your ACME certificates.
### ACME Challenge
There are two kind of `storage` :
#### TLS Challenge
- a JSON file,
- a KV store entry.
!!! danger "DEPRECATED"
`storage` replaces `storageFile` which is deprecated.
!!! note
During Træfik configuration migration from a configuration file to a KV store (thanks to `storeconfig` subcommand as described [here](/user-guide/kv-config/#store-configuration-in-key-value-store)), if ACME certificates have to be migrated too, use both `storageFile` and `storage`.
- `storageFile` will contain the path to the `acme.json` file to migrate.
- `storage` will contain the key where the certificates will be stored.
#### Store data in a file
ACME certificates can be stored in a JSON file which with the `600` right mode.
There are two ways to store ACME certificates in a file from Docker:
- create a file on your host and mount it as a volume:
```toml
storage = "acme.json"
```
```bash
docker run -v "/my/host/acme.json:acme.json" traefik
```
- mount the folder containing the file as a volume
```toml
storage = "/etc/traefik/acme/acme.json"
```
```bash
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
```
!!! warning
This file cannot be shared per many instances of Træfik at the same time.
If you have to use Træfik cluster mode, please use [a KV Store entry](/configuration/acme/#storage-kv-entry).
#### Store data in a KV store entry
ACME certificates can be stored in a KV Store entry.
Use the `TLS-ALPN-01` challenge to generate and renew ACME certificates by provisioning a TLS certificate.
```toml
storage = "traefik/acme/account"
[acme]
# ...
entryPoint = "https"
[acme.tlsChallenge]
```
**This kind of storage is mandatory in cluster mode.**
#### `httpChallenge`
Because KV stores (like Consul) have limited entries size, the certificates list is compressed before to be set in a KV store entry.
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning a HTTP resource under a well-known URI.
!!! note
It's possible to store up to approximately 100 ACME certificates in Consul.
### `httpChallenge`
Use `HTTP-01` challenge to generate/renew ACME certificates.
The redirection is fully compatible with the HTTP-01 challenge.
You can use redirection with HTTP-01 challenge without problem.
Redirection is fully compatible with the `HTTP-01` challenge.
```toml
[acme]
@@ -236,7 +189,11 @@ entryPoint = "https"
entryPoint = "http"
```
#### `entryPoint`
!!! note
If the `HTTP-01` challenge is used, `acme.httpChallenge.entryPoint` has to be defined and reachable by Let's Encrypt through port 80.
This is a Let's Encrypt limitation as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
##### `entryPoint`
Specify the entryPoint to use during the challenges.
@@ -259,12 +216,11 @@ defaultEntryPoints = ["http", "https"]
```
!!! note
`acme.httpChallenge.entryPoint` has to be reachable by Let's Encrypt through the port 80.
It's a Let's Encrypt limitation as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
`acme.httpChallenge.entryPoint` has to be reachable through port 80. It's a Let's Encrypt limitation as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
### `dnsChallenge`
#### `dnsChallenge`
Use `DNS-01/DNS-02` challenge to generate/renew ACME certificates.
Use the `DNS-01` challenge to generate and renew ACME certificates by provisioning a DNS record.
```toml
[acme]
@@ -275,50 +231,106 @@ Use `DNS-01/DNS-02` challenge to generate/renew ACME certificates.
# ...
```
!!! note
ACME wildcard certificates can only be generated thanks to a `DNS-02` challenge.
##### `delayBeforeCheck`
#### `provider`
Select the provider that matches the DNS domain that will host the challenge TXT record, and provide environment variables to enable setting it:
| Provider Name | Provider code | Configuration |
|--------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------|
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` |
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP` |
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CLOUDFLARE_EMAIL`, `CLOUDFLARE_API_KEY` - The Cloudflare `Global API Key` needs to be used and not the `Origin CA Key` |
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` |
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` |
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` |
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` |
| [DNSPod](http://www.dnspod.net/) | `dnspod` | `DNSPOD_API_KEY` |
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` |
| [Exoscale](https://www.exoscale.ch) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` |
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` |
| [Gandi V5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` |
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` |
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` |
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` |
| manual | - | none, but run Træfik interactively & turn on `acmeLogging` to see instructions & press <kbd>Enter</kbd>. |
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` |
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` |
| [Open Telekom Cloud](https://cloud.telekom.de/en/) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` |
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` |
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` |
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` |
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` |
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `AWS_HOSTED_ZONE_ID` or configured user/instance IAM profile. |
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` |
#### `delayBeforeCheck`
By default, the `provider` will verify the TXT DNS challenge record before letting ACME verify.
If `delayBeforeCheck` is greater than zero, avoid this & instead just wait so many seconds.
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.
Useful if internal networks block external DNS queries.
!!! note
This field has no sense if a `provider` is not defined.
A `provider` is mandatory.
##### `provider`
Here is a list of supported `provider`s, that can automate the DNS verification, along with the required environment variables and their [wildcard & root domain support](/configuration/acme/#wildcard-domains) for each. Do not hesitate to complete it.
| Provider Name | Provider Code | Environment Variables | Wildcard & Root Domain Support |
|--------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------------------------------------|--------------------------------|
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | Not tested yet |
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP` | Not tested yet |
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | Not tested yet |
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CLOUDFLARE_EMAIL`, `CLOUDFLARE_API_KEY` - The `Global API Key` needs to be used, not the `Origin CA Key` | YES |
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | Not tested yet |
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | YES |
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | Not tested yet |
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | Not tested yet |
| [DNSPod](http://www.dnspod.net/) | `dnspod` | `DNSPOD_API_KEY` | Not tested yet |
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | Not tested yet |
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | Not tested yet |
| External Program | `exec` | `EXEC_PATH` | Not tested yet |
| [Exoscale](https://www.exoscale.ch) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | YES |
| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | Not tested yet |
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | Not tested yet |
| [Gandi V5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | YES |
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | Not tested yet |
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | Not tested yet |
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` | YES |
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | Not tested yet |
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | Not tested yet |
| manual | - | none, but you need to run Træfik interactively, turn on `acmeLogging` to see instructions and press <kbd>Enter</kbd>. | YES |
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | Not tested yet |
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | Not tested yet |
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | Not tested yet |
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | Not tested yet |
| [Open Telekom Cloud](https://cloud.telekom.de/en/) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | Not tested yet |
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | YES |
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | Not tested yet |
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | Not tested yet |
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | Not tested yet |
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `AWS_HOSTED_ZONE_ID` or a configured user/instance IAM profile. | YES |
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | Not tested yet |
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | Not tested yet |
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | Not tested yet |
### `domains`
You can provide SANs (alternative domains) to each main domain.
All domains must have A/AAAA records pointing to Træfik.
Each domain & SAN will lead to a certificate request.
```toml
[acme]
# ...
[[acme.domains]]
main = "local1.com"
sans = ["test1.local1.com", "test2.local1.com"]
[[acme.domains]]
main = "local2.com"
[[acme.domains]]
main = "*.local3.com"
sans = ["local3.com", "test1.test1.local3.com"]
# ...
```
!!! warning
Take note that Let's Encrypt applies [rate limiting](https://letsencrypt.org/docs/rate-limits).
!!! note
Wildcard certificates can only be verified through a `DNS-01` challenge.
#### Wildcard Domains
[ACME V2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) allows wildcard certificate support.
As described in [Let's Encrypt's post](https://community.letsencrypt.org/t/staging-endpoint-for-acme-v2/49605) wildcard certificates can only be generated through a [`DNS-01` challenge](/configuration/acme/#dnschallenge).
```toml
[acme]
# ...
[[acme.domains]]
main = "*.local1.com"
sans = ["local1.com"]
# ...
```
It is not possible to request a double wildcard certificate for a domain (for example `*.*.local.com`).
Due to ACME limitation it is not possible to define wildcards in SANs (alternative domains). Thus, the wildcard domain has to be defined as a main domain.
Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 `DNS-01` challenges are executed.
In this case the generated DNS TXT record for both domains is the same.
Eventhough this behaviour is [DNS RFC](https://community.letsencrypt.org/t/wildcard-issuance-two-txt-records-for-the-same-name/54528/2) compliant, it can lead to problems as all DNS providers keep DNS records cached for a certain time (TTL) and this TTL can be superior to the challenge timeout making the `DNS-01` challenge fail.
The Træfik ACME client library [LEGO](https://github.com/xenolf/lego) supports some but not all DNS providers to work around this issue.
The [`provider` table](/configuration/acme/#provider) indicates if they allow generating certificates for a wildcard domain and its root domain.
### `onDemand` (Deprecated)
@@ -332,15 +344,15 @@ onDemand = true
# ...
```
Enable on demand certificate.
Enable on demand certificate generation.
This will request a certificate from Let's Encrypt during the first TLS handshake for a host name that does not yet have a certificate.
This will request certificates from Let's Encrypt during the first TLS handshake for host names that do not yet have certificates.
!!! warning
TLS handshakes will be slow when requesting a host name certificate for the first time, this can lead to DoS attacks.
TLS handshakes are slow when requesting a host name certificate for the first time. This can lead to DoS attacks!
!!! warning
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits).
Take note that Let's Encrypt applies [rate limiting](https://letsencrypt.org/docs/rate-limits).
### `onHostRule`
@@ -351,112 +363,94 @@ onHostRule = true
# ...
```
Enable certificate generation on frontends `Host` rules (for frontends wired on the `acme.entryPoint`).
Enable certificate generation on frontend `Host` rules (for frontends wired to the `acme.entryPoint`).
This will request a certificate from Let's Encrypt for each frontend with a Host rule.
For example, a rule `Host:test1.traefik.io,test2.traefik.io` will request a certificate with main domain `test1.traefik.io` and SAN `test2.traefik.io`.
For example, the rule `Host:test1.traefik.io,test2.traefik.io` will request a certificate with main domain `test1.traefik.io` and SAN `test2.traefik.io`.
!!! warning
`onHostRule` option can not be used to generate wildcard certificates.
Refer to [the wildcard generation section](/configuration/acme/#wildcard-domain) for more information.
Refer to [wildcard generation](/configuration/acme/#wildcard-domains) for further information.
### `caServer`
### `storage`
The `storage` option sets the location where your ACME certificates are saved to.
```toml
[acme]
# ...
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
storage = "acme.json"
# ...
```
CA server to use.
The value can refer to two kinds of storage:
- Uncomment the line to run on the staging Let's Encrypt server.
- Leave comment to go to prod.
- a JSON file
- a KV store entry
### `domains`
!!! danger "DEPRECATED"
`storage` replaces `storageFile` which is deprecated.
!!! note
During migration to a KV store use both `storageFile` and `storage` to migrate ACME certificates too. See [`storeconfig` subcommand](/user-guide/kv-config/#store-configuration-in-key-value-store) for further information.
#### As a File
ACME certificates can be stored in a JSON file that needs to have file mode `600`.
In Docker you can either mount the JSON file or the folder containing it:
```bash
docker run -v "/my/host/acme.json:acme.json" traefik
```
```bash
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
```
!!! warning
This file cannot be shared across multiple instances of Træfik at the same time. Please use a [KV Store entry](/configuration/acme/#as-a-key-value-store-entry) instead.
#### As a Key Value Store Entry
ACME certificates can be stored in a KV Store entry. This kind of storage is **mandatory in cluster mode**.
```toml
[acme]
# ...
[[acme.domains]]
main = "local1.com"
sans = ["test1.local1.com", "test2.local1.com"]
[[acme.domains]]
main = "local2.com"
sans = ["test1.local2.com", "test2.local2.com"]
[[acme.domains]]
main = "local3.com"
[[acme.domains]]
main = "*.local4.com"
# ...
storage = "traefik/acme/account"
```
#### Wildcard domains
Because KV stores (like Consul) have limited entry size the certificates list is compressed before it is saved as KV store entry.
Wildcard domain has to be defined as a main domain **with no SANs** (alternative domains).
All domains must have A/AAAA records pointing to Træfik.
!!! note
It is possible to store up to approximately 100 ACME certificates in Consul.
!!! warning
Note that Let's Encrypt has [rate limiting](https://letsencrypt.org/docs/rate-limits).
#### ACME v2 Migration
Each domain & SANs will lead to a certificate request.
During migration from ACME v1 to ACME v2, using a storage file, a backup of the original file is created in the same place as the latter (with a `.bak` extension).
#### Others domains
For example: if `acme.storage`'s value is `/etc/traefik/acme/acme.json`, the backup file will be `/etc/traefik/acme/acme.json.bak`.
You can provide SANs (alternative domains) to each main domain.
All domains must have A/AAAA records pointing to Træfik.
!!! warning
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits).
Each domain & SANs will lead to a certificate request.
!!! note
When Træfik is launched in a container, the storage file's parent directory needs to be mounted to be able to access the backup file on the host.
Otherwise the backup file will be deleted when the container is stopped. Træfik will only generate it once!
### `dnsProvider` (Deprecated)
!!! danger "DEPRECATED"
This option is deprecated, use [dnsChallenge.provider](/configuration/acme/#dnschallenge) instead.
This option is deprecated. Please use [dnsChallenge.provider](/configuration/acme/#provider) instead.
### `delayDontCheckDNS` (Deprecated)
!!! danger "DEPRECATED"
This option is deprecated, use [dnsChallenge.delayBeforeCheck](/configuration/acme/#dnschallenge) instead.
This option is deprecated. Please use [dnsChallenge.delayBeforeCheck](/configuration/acme/#dnschallenge) instead.
## Wildcard certificates
## Fallbacks
[ACME V2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) allows wildcard certificate support.
However, this feature needs a specific configuration.
If Let's Encrypt is not reachable, these certificates will be used:
### DNS-02 Challenge
1. ACME certificates already generated before downtime
1. Expired ACME certificates
1. Provided certificates
As described in [Let's Encrypt post](https://community.letsencrypt.org/t/staging-endpoint-for-acme-v2/49605), wildcard certificates can only be generated through a `DNS-02`Challenge.
This challenge is linked to the Træfik option `acme.dnsChallenge`.
```toml
[acme]
# ...
[acme.dnsChallenge]
provider = "digitalocean"
delayBeforeCheck = 0
# ...
```
For more information about this option, please refer to the [dnsChallenge section](/configuration/acme/#dnschallenge).
### Wildcard domain
Wildcard domains can currently be provided only by to the `acme.domains` option.
Theses domains can not have SANs.
```toml
[acme]
# ...
[[acme.domains]]
main = "*local1.com"
[[acme.domains]]
main = "*.local2.com"
# ...
```
For more information about this option, please refer to the [domains section](/configuration/acme/#domains).
!!! note
For new (sub)domains which need Let's Encrypt authentification, the default Træfik certificate will be used until Træfik is restarted.

View File

@@ -21,7 +21,7 @@
# Enable debug mode.
# This will install HTTP handlers to expose Go expvars under /debug/vars and
# pprof profiling data under /debug/pprof.
# pprof profiling data under /debug/pprof/.
# Additionally, the log level will be set to DEBUG.
#
# Optional
@@ -30,7 +30,7 @@
debug = true
```
For more customization, see [entry points](/configuration/entrypoints/) documentation and [examples](/user-guide/examples/#ping-health-check).
For more customization, see [entry points](/configuration/entrypoints/) documentation and the examples below.
## Web UI

View File

@@ -1,13 +1,13 @@
# BoltDB Backend
# BoltDB Provider
Træfik can be configured to use BoltDB as a backend configuration.
Træfik can be configured to use BoltDB as a provider.
```toml
################################################################
# BoltDB configuration backend
# BoltDB Provider
################################################################
# Enable BoltDB configuration backend.
# Enable BoltDB Provider.
[boltdb]
# BoltDB file.
@@ -53,7 +53,7 @@ filename = "boltdb.tmpl"
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/boltdb.crt"
# key = "/etc/ssl/boltdb.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).

View File

@@ -1,13 +1,13 @@
# Consul Key-Value Backend
# Consul Key-Value Provider
Træfik can be configured to use Consul as a backend configuration.
Træfik can be configured to use Consul as a provider.
```toml
################################################################
# Consul KV configuration backend
# Consul KV Provider
################################################################
# Enable Consul KV configuration backend.
# Enable Consul KV Provider.
[consul]
# Consul server endpoint.
@@ -53,9 +53,9 @@ prefix = "traefik"
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/consul.crt"
# key = "/etc/ssl/consul.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-value-storage-structure) section to get documentation on Traefik KV structure.

View File

@@ -1,13 +1,13 @@
# Consul Catalog backend
# Consul Catalog Provider
Træfik can be configured to use service discovery catalog of Consul as a backend configuration.
Træfik can be configured to use service discovery catalog of Consul as a provider.
```toml
################################################################
# Consul Catalog configuration backend
# Consul Catalog Provider
################################################################
# Enable Consul Catalog configuration backend.
# Enable Consul Catalog Provider.
[consulCatalog]
# Consul server endpoint.
@@ -24,6 +24,13 @@ endpoint = "127.0.0.1:8500"
#
exposedByDefault = false
# Allow Consul server to serve the catalog reads regardless of whether it is the leader.
#
# Optional
# Default: false
#
stale = false
# Default domain used.
#
# Optional
@@ -57,12 +64,28 @@ prefix = "traefik"
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/consul.crt"
# key = "/etc/ssl/consul.key"
# insecureskipverify = true
# insecureSkipVerify = true
# Override default configuration template.
# For advanced users :)
#
# Optional
#
# filename = "consulcatalog.tmpl"
# Override template version
# For advanced users :)
#
# Optional
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = 2
```
This backend will create routes matching on hostname based on the service name used in Consul.
This provider will create routes matching on hostname based on the service name used in Consul.
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Tags
@@ -71,46 +94,62 @@ Additional settings can be defined using Consul Catalog tags.
!!! note
The default prefix is `traefik`.
| Label | Description |
|-------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<prefix>.enable=false` | Disable this container in Træfik. |
| `<prefix>.port=80` | Register this port. Useful when the container exposes multiples ports. |
| `<prefix>.protocol=https` | Override the default `http` protocol. |
| `<prefix>.weight=10` | Assign this weight to the container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
| `<prefix>.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `<prefix>.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `<prefix>.backend.healthcheck.interval=1s` | Define the health check interval. |
| `<prefix>.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm. |
| `<prefix>.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions. |
| `<prefix>.backend.loadbalancer.sticky=true` | Enable backend sticky sessions. (DEPRECATED) |
| `<prefix>.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `<prefix>.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `<prefix>.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `<prefix>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `<prefix>.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `<prefix>.frontend.priority=10` | Override default frontend priority. |
| `<prefix>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
| `<prefix>.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `<prefix>.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `<prefix>.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `<prefix>.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. |
| `<prefix>.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `<prefix>.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|-------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<prefix>.enable=false` | Disables this container in Træfik. |
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
| `<prefix>.weight=10` | Assigns this weight to the container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `<prefix>.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `<prefix>.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `<prefix>.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `<prefix>.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `<prefix>.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. |
| `<prefix>.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. |
| `<prefix>.backend.loadbalancer.sticky=true` | Enables backend sticky sessions. (DEPRECATED) |
| `<prefix>.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `<prefix>.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `<prefix>.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `<prefix>.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `<prefix>.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `<prefix>.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `<prefix>.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `<prefix>.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `<prefix>.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `<prefix>.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `<prefix>.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `<prefix>.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `<prefix>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `<prefix>.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `<prefix>.frontend.priority=10` | Overrides default frontend priority. |
| `<prefix>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). |
| `<prefix>.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `<prefix>.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `<prefix>.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `<prefix>.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. |
| `<prefix>.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `<prefix>.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
### Custom Headers
@@ -130,25 +169,27 @@ Additional settings can be defined using Consul Catalog tags.
| Label | Description |
|-----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<prefix>.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `<prefix>.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `<prefix>.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `<prefix>.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `<prefix>.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `<prefix>.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `<prefix>.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `<prefix>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `<prefix>.frontend.headers.hostsProxyHeaders=EXPR` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `<prefix>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `<prefix>.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `<prefix>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `<prefix>.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `<prefix>.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `<prefix>.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `<prefix>.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `<prefix>.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `<prefix>.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `<prefix>.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `<prefix>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `<prefix>.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `<prefix>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `<prefix>.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `<prefix>.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `<prefix>.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `<prefix>.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `<prefix>.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `<prefix>.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `<prefix>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `<prefix>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
### Examples
If you want that Træfik uses Consul tags correctly you need to defined them like that:

View File

@@ -1,16 +1,16 @@
# Docker Backend
# Docker Provider
Træfik can be configured to use Docker as a backend configuration.
Træfik can be configured to use Docker as a provider.
## Docker
```toml
################################################################
# Docker configuration backend
# Docker Provider
################################################################
# Enable Docker configuration backend.
# Enable Docker Provider.
[docker]
# Docker server endpoint. Can be a tcp or a unix socket endpoint.
@@ -46,7 +46,7 @@ watch = true
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = "2"
# templateVersion = 2
# Expose containers by default in Traefik.
# If set to false, containers that don't have `traefik.enable=true` will be ignored.
@@ -54,7 +54,7 @@ watch = true
# Optional
# Default: true
#
exposedbydefault = true
exposedByDefault = true
# Use the IP address from the binded port instead of the inner network one.
# For specific use-case :)
@@ -69,7 +69,14 @@ usebindportip = true
# Optional
# Default: false
#
swarmmode = false
swarmMode = false
# Define a default docker network to use for connections to all containers.
# Can be overridden by the traefik.docker.network label.
#
# Optional
#
network = "web"
# Enable docker TLS connection.
#
@@ -79,20 +86,20 @@ swarmmode = false
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/docker.crt"
# key = "/etc/ssl/docker.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Docker Swarm Mode
```toml
################################################################
# Docker Swarmmode configuration backend
# Docker Swarm Mode Provider
################################################################
# Enable Docker configuration backend.
# Enable Docker Provider.
[docker]
# Docker server endpoint.
@@ -123,7 +130,14 @@ watch = true
# Optional
# Default: false
#
swarmmode = true
swarmMode = true
# Define a default docker network to use for connections to all containers.
# Can be overridden by the traefik.docker.network label.
#
# Optional
#
network = "web"
# Override default configuration template.
# For advanced users :)
@@ -139,14 +153,14 @@ swarmmode = true
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = "2"
# templateVersion = 2
# Expose services by default in Traefik.
#
# Optional
# Default: true
#
exposedbydefault = false
exposedByDefault = false
# Enable docker TLS connection.
#
@@ -156,10 +170,10 @@ exposedbydefault = false
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/docker.crt"
# key = "/etc/ssl/docker.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Labels: overriding default behavior
@@ -193,55 +207,79 @@ services:
Labels can be used on containers to override default behavior.
| Label | Description |
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.docker.network` | Set the docker network to use for connections to this container. [1] |
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
| `traefik.protocol=https` | Override the default `http` protocol |
| `traefik.weight=10` | Assign this weight to the container |
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
| `traefik.backend.loadbalancer.swarm=true` | Use Swarm's inbuilt load balancer (only relevant under Swarm Mode). |
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Override default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] |
| `traefik.domain` | Sets the default domain for the frontend rules. |
| `traefik.enable=false` | Disables this container in Træfik. |
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
| `traefik.protocol=https` | Overrides the default `http` protocol |
| `traefik.weight=10` | Assigns this weight to the container |
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.loadbalancer.swarm=true` | Uses Swarm's inbuilt load balancer (only relevant under Swarm Mode). |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2] (DEPRECATED). |
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2]. |
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header user to pass the authenticated user to the application. |
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Overrides default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
[1] `traefik.docker.network`:
If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them).
For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name.
Or if your service references external network use it's name instead.
[2] `traefik.frontend.auth.basic.users=EXPR `:
To create `user:password` pair, it's possible to use this command:
`echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g`.
The result will be `user:$$apr1$$9Cv/OMGj$$ZomWQzuQbL.3TRCS81A1g/`, note additional symbol `$` makes escaping.
#### Custom Headers
| Label | Description |
@@ -254,24 +292,25 @@ Or if your service references external network use it's name instead.
| Label | Description |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
### On containers with Multiple Ports (segment labels)
@@ -281,62 +320,78 @@ You can define as many segments as ports exposed in a container.
Segment labels override the default behavior.
| Label | Description |
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the segment labels could be used. |
| `traefik.<segment_name>.protocol` | Overrides `traefik.protocol`. |
| `traefik.<segment_name>.weight` | Assign this segment weight. Overrides `traefik.weight`. |
| `traefik.<segment_name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
| `traefik.<segment_name>.frontend.backend=BACKEND` | Assign this segment frontend to `BACKEND`. Default is to assign to the segment backend. |
| `traefik.<segment_name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
| `traefik.<segment_name>.frontend.passTLSCert` | Overrides `traefik.frontend.passTLSCert`. |
| `traefik.<segment_name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Overrides `traefik.frontend.redirect.entryPoint`. |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Overrides `traefik.frontend.redirect.regex`. |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Overrides `traefik.frontend.redirect.replacement`. |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.<segment_name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Overrides `traefik.frontend.whiteList.sourceRange`. |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Overrides `traefik.frontend.whiteList.useXForwardedFor`. |
| Label | Description |
|---------------------------------------------------------------------------|---------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersfile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersfile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersfile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersfile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify`|
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
#### Custom Headers
| Label | Description |
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container.<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client.<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| Label | Description |
|----------------------------------------------------------------------|----------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | Same as `traefik.frontend.headers.customRequestHeaders` |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | Same as `traefik.frontend.headers.customResponseHeaders` |
#### Security Headers
| Label | Description |
|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| Label | Description |
|-------------------------------------------------------------------------|--------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | Same as `traefik.frontend.headers.allowedHosts` |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | Same as `traefik.frontend.headers.browserXSSFilter` |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | Same as `traefik.frontend.headers.contentSecurityPolicy` |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | Same as `traefik.frontend.headers.contentTypeNosniff` |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | Same as `traefik.frontend.headers.customBrowserXSSValue` |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | Same as `traefik.frontend.headers.customFrameOptionsValue` |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | Same as `traefik.frontend.headers.forceSTSHeader` |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | Same as `traefik.frontend.headers.frameDeny` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR` | Same as `traefik.frontend.headers.hostsProxyHeaders` |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | Same as `traefik.frontend.headers.isDevelopment` |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | Same as `traefik.frontend.headers.publicKey` |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | Same as `traefik.frontend.headers.referrerPolicy` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | Same as `traefik.frontend.headers.SSLRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | Same as `traefik.frontend.headers.SSLTemporaryRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | Same as `traefik.frontend.headers.SSLHost` |
| `traefik.<segment_name>.frontend.headers.SSLForceHost=true` | Same as `traefik.frontend.headers.SSLForceHost` |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | Same as `traefik.frontend.headers.SSLProxyHeaders=EXPR` |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | Same as `traefik.frontend.headers.STSSeconds=315360000` |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | Same as `traefik.frontend.headers.STSIncludeSubdomains=true` |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | Same as `traefik.frontend.headers.STSPreload=true` |
!!! note
If a label is defined both as a `container label` and a `segment label` (for example `traefik.<segment_name>.port=PORT` and `traefik.port=PORT` ), the `segment label` is used to defined the `<segment_name>` property (`port` in the example).

View File

@@ -1,15 +1,15 @@
# DynamoDB Backend
# DynamoDB Provider
Træfik can be configured to use Amazon DynamoDB as a backend configuration.
Træfik can be configured to use Amazon DynamoDB as a provider.
## Configuration
```toml
################################################################
# DynamoDB configuration backend
# DynamoDB Provider
################################################################
# Enable DynamoDB configuration backend.
# Enable DynamoDB Provider.
[dynamodb]
# Region to use when connecting to AWS.
@@ -39,13 +39,13 @@ watch = true
#
refreshSeconds = 15
# AccessKeyID to use when connecting to AWS.
# Access Key ID to use when connecting to AWS.
#
# Optional
#
accessKeyID = "abc"
# SecretAccessKey to use when connecting to AWS.
# Secret Access Key to use when connecting to AWS.
#
# Optional
#
@@ -68,4 +68,3 @@ Items in the `dynamodb` table must have three attributes:
See `types/types.go` for details.
The presence or absence of this attribute determines its type.
So an item should never have both a `frontend` and a `backend` attribute.

View File

@@ -1,15 +1,15 @@
# ECS Backend
# ECS Provider
Træfik can be configured to use Amazon ECS as a backend configuration.
Træfik can be configured to use Amazon ECS as a provider.
## Configuration
```toml
################################################################
# ECS configuration backend
# ECS Provider
################################################################
# Enable ECS configuration backend.
# Enable ECS Provider.
[ecs]
# ECS Cluster Name.
@@ -33,6 +33,7 @@ clusters = ["default"]
watch = true
# Default domain used.
# Can be overridden by setting the "traefik.domain" label.
#
# Optional
# Default: ""
@@ -66,13 +67,13 @@ exposedByDefault = false
#
region = "us-east-1"
# AccessKeyID to use when connecting to AWS.
# Access Key ID to use when connecting to AWS.
#
# Optional
#
accessKeyID = "abc"
# SecretAccessKey to use when connecting to AWS.
# Secret Access Key to use when connecting to AWS.
#
# Optional
#
@@ -84,14 +85,25 @@ secretAccessKey = "123"
# Optional
#
# filename = "ecs.tmpl"
# Override template version
# For advanced users :)
#
# Optional
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = 2
```
If `AccessKeyID`/`SecretAccessKey` is not given credentials will be resolved in the following order:
If `accessKeyID`/`secretAccessKey` is not given credentials will be resolved in the following order:
- From environment variables; `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
- Shared credentials, determined by `AWS_PROFILE` and `AWS_SHARED_CREDENTIALS_FILE`, defaults to `default` and `~/.aws/credentials`.
- EC2 instance role or ECS task role
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Policy
Træfik needs the following policy to read ECS information:
@@ -124,47 +136,66 @@ Træfik needs the following policy to read ECS information:
Labels can be used on task containers to override default behaviour:
| Label | Description |
|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.port=80` | Override the default `port` value. Overrides `NetworkBindings` from Docker Container |
| `traefik.protocol=https` | Override the default `http` protocol |
| `traefik.weight=10` | Assign this weight to the container |
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. (Default: 30s) |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Override default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{instance_name}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.domain` | Sets the default domain for frontend rules. |
| `traefik.enable=false` | Disables this container in Træfik. |
| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container |
| `traefik.protocol=https` | Overrides the default `http` protocol |
| `traefik.weight=10` | Assigns this weight to the container |
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie manually name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Overrides default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{instance_name}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
### Custom Headers
@@ -178,21 +209,22 @@ Labels can be used on task containers to override default behaviour:
| Label | Description |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |

View File

@@ -1,13 +1,13 @@
# Etcd Backend
# Etcd Provider
Træfik can be configured to use Etcd as a backend configuration.
Træfik can be configured to use Etcd as a provider.
```toml
################################################################
# Etcd configuration backend
# Etcd Provider
################################################################
# Enable Etcd configuration backend.
# Enable Etcd Provider.
[etcd]
# Etcd server endpoint.
@@ -63,10 +63,10 @@ useAPIV3 = true
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/etcd.crt"
# key = "/etc/ssl/etcd.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-value-storage-structure) section to get documentation on Traefik KV structure.

View File

@@ -1,13 +1,13 @@
# Eureka Backend
# Eureka Provider
Træfik can be configured to use Eureka as a backend configuration.
Træfik can be configured to use Eureka as a provider.
```toml
################################################################
# Eureka configuration backend
# Eureka Provider
################################################################
# Enable Eureka configuration backend.
# Enable Eureka Provider.
[eureka]
# Eureka server endpoint.

View File

@@ -1,4 +1,4 @@
# File Backends
# File Provider
Træfik can be configured with a file.
@@ -37,6 +37,11 @@ Træfik can be configured with a file.
path = "/health"
port = 88
interval = "30s"
scheme = "http"
hostname = "myhost.com"
[backends.backend1.healthcheck.headers]
My-Custom-Header = "foo"
My-Header = "bar"
[backends.backend2]
# ...
@@ -50,11 +55,40 @@ Træfik can be configured with a file.
passHostHeader = true
passTLSCert = true
priority = 42
# Use frontends.frontend1.auth.basic below instead
basicAuth = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
[frontends.frontend1.auth]
headerField = "X-WebAuth-User"
[frontends.frontend1.auth.basic]
removeHeader = true
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
usersFile = "/path/to/.htpasswd"
[frontends.frontend1.auth.digest]
removeHeader = true
users = [
"test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
]
usersFile = "/path/to/.htdigest"
[frontends.frontend1.auth.forward]
address = "https://authserver.com/auth"
trustForwardHeader = true
authResponseHeaders = ["X-Auth-User"]
[frontends.frontend1.auth.forward.tls]
ca = "path/to/local.crt"
caOptional = true
cert = "path/to/foo.cert"
key = "path/to/foo.key"
insecureSkipVerify = true
[frontends.frontend1.whiteList]
sourceRange = ["10.42.0.0/16", "152.89.1.33/32", "afed:be44::/16"]
useXForwardedFor = true
@@ -140,19 +174,20 @@ Træfik can be configured with a file.
# ...
```
## Configuration mode
## Configuration Mode
You have three choices:
You have two choices:
- [Simple](/configuration/backends/file/#simple)
- [Rules in a Separate File](/configuration/backends/file/#rules-in-a-separate-file)
- [Multiple `.toml` Files](/configuration/backends/file/#multiple-toml-files)
- [Rules in Træfik configuration file](/configuration/backends/file/#rules-in-trfik-configuration-file)
- [Rules in dedicated files](/configuration/backends/file/#rules-in-dedicated-files)
To enable the file backend, you must either pass the `--file` option to the Træfik binary or put the `[file]` section (with or without inner settings) in the configuration file.
The configuration file allows managing both backends/frontends and HTTPS certificates (which are not [Let's Encrypt](https://letsencrypt.org) certificates generated through Træfik).
### Simple
TOML templating can be used if rules are not defined in the Træfik configuration file.
### Rules in Træfik Configuration File
Add your configuration at the end of the global configuration file `traefik.toml`:
@@ -197,9 +232,16 @@ defaultEntryPoints = ["http", "https"]
Adding certificates directly to the entryPoint is still maintained but certificates declared in this way cannot be managed dynamically.
It's recommended to use the file provider to declare certificates.
### Rules in a Separate File
!!! warning
TOML templating cannot be used if rules are defined in the Træfik configuration file.
Put your rules in a separate file, for example `rules.toml`:
### Rules in Dedicated Files
Træfik allows defining rules in one or more separate files.
#### One Separate File
You have to specify the file path in the `file.filename` option.
```toml
# traefik.toml
@@ -213,8 +255,31 @@ defaultEntryPoints = ["http", "https"]
[file]
filename = "rules.toml"
watch = true
```
The option `file.watch` allows Træfik to watch file changes automatically.
#### Multiple Separated Files
You could have multiple `.toml` files in a directory (and recursively in its sub-directories):
```toml
[file]
directory = "/path/to/config/"
watch = true
```
The option `file.watch` allows Træfik to watch file changes automatically.
#### Separate Files Content
If you are defining rules in one or more separate files, you can use two formats.
##### Simple Format
Backends, Frontends and TLS certificates are defined one at time, as described in the file `rules.toml`:
```toml
# rules.toml
[backends]
@@ -239,18 +304,34 @@ defaultEntryPoints = ["http", "https"]
# ...
```
### Multiple `.toml` Files
##### TOML Templating
You could have multiple `.toml` files in a directory (and recursively in its sub-directories):
!!! warning
TOML templating can only be used **if rules are defined in one or more separate files**.
Templating will not work in the Træfik configuration file.
Træfik allows using TOML templating.
Thus, it's possible to define easily lot of Backends, Frontends and TLS certificates as described in the file `template-rules.toml` :
```toml
[file]
directory = "/path/to/config/"
```
# template-rules.toml
[backends]
{{ range $i, $e := until 100 }}
[backends.backend{{ $e }}]
#...
{{ end }}
If you want Træfik to watch file changes automatically, just add:
[frontends]
{{ range $i, $e := until 100 }}
[frontends.frontend{{ $e }}]
#...
{{ end }}
```toml
[file]
watch = true
# HTTPS certificate
{{ range $i, $e := until 100 }}
[[tls]]
#...
{{ end }}
```

View File

@@ -1,6 +1,6 @@
# Kubernetes Ingress Backend
# Kubernetes Ingress Provider
Træfik can be configured to use Kubernetes Ingress as a backend configuration.
Træfik can be configured to use Kubernetes Ingress as a provider.
See also [Kubernetes user guide](/user-guide/kubernetes).
@@ -8,10 +8,10 @@ See also [Kubernetes user guide](/user-guide/kubernetes).
```toml
################################################################
# Kubernetes Ingress configuration backend
# Kubernetes Ingress Provider
################################################################
# Enable Kubernetes Ingress configuration backend.
# Enable Kubernetes Ingress Provider.
[kubernetes]
# Kubernetes server endpoint.
@@ -54,8 +54,6 @@ See also [Kubernetes user guide](/user-guide/kubernetes).
# 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.
#
# Note : `ingressClass` option must begin with the "traefik" prefix.
#
# Optional
# Default: empty
#
@@ -81,6 +79,20 @@ See also [Kubernetes user guide](/user-guide/kubernetes).
# Default: <built-in template>
#
# filename = "kubernetes.tmpl"
# Enable IngressEndpoint configuration.
# This will allow Traefik to update the status section of ingress objects, if desired.
#
# Optional
#
# [kubernetes.ingressEndpoint]
#
# At least one must be configured.
# `publishedservice` will override the `hostname` and `ip` settings if configured.
#
# hostname = "localhost"
# ip = "127.0.0.1"
# publishedService = "namespace/servicename"
```
### `endpoint`
@@ -105,6 +117,12 @@ A label selector can be defined to filter on specific Ingress objects only.
See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details.
### `ingressEndpoint`
You can configure a static hostname or IP address that Traefik will add to the status section of Ingress objects that it manages.
If you prefer, you can provide a service, which traefik will copy the status spec from.
This will give more flexibility in cloud/dynamic environments.
### TLS communication between Traefik and backend pods
Traefik automatically requests endpoint information based on the service provided in the ingress spec.
@@ -112,9 +130,9 @@ Although traefik will connect directly to the endpoints (pods), it still checks
If the service port defined in the ingress spec is 443, then the backend communication protocol is assumed to be TLS, and will connect via TLS automatically.
!!! note
Please note that by enabling TLS communication between traefik and your pods, you will have to have trusted certificates that have the proper trust chain and IP subject name.
Please note that by enabling TLS communication between traefik and your pods, you will have to have trusted certificates that have the proper trust chain and IP subject name.
If this is not an option, you may need to skip TLS certificate verification.
See the [InsecureSkipVerify](/configuration/commons/#main-section) setting for more details.
See the [insecureSkipVerify](/configuration/commons/#main-section) setting for more details.
## Annotations
@@ -122,23 +140,27 @@ If the service port defined in the ingress spec is 443, then the backend communi
The following general annotations are applicable on the Ingress object:
| Annotation | Description |
|---------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.ingress.kubernetes.io/buffering: <YML>` | (3) See [buffering](/configuration/commons/#buffering) section. |
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | (1) See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`. |
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | (2) See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. |
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access. all source IPs are permitted if the list is empty or a single range is ill-formatted. |
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) |
| Annotation | Description |
|---------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
| `traefik.ingress.kubernetes.io/buffering: <YML>` | (3) See [buffering](/configuration/commons/#buffering) section. |
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | (1) See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`. |
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | (2) See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines). Note: ReplacePath is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`. |
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. |
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (6). |
| `ingress.kubernetes.io/whitelist-x-forwarded-for: "true"` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) |
| `traefik.ingress.kubernetes.io/service-weights: <YML>` | Set ingress backend weights specified as percentage or decimal numbers in YAML. (5) |
<1> `traefik.ingress.kubernetes.io/error-pages` example:
@@ -183,8 +205,43 @@ retryexpression: IsNetworkError() && Attempts() <= 2
<4> `traefik.ingress.kubernetes.io/app-root`:
Non-root paths will not be affected by this annotation and handled normally.
This annotation may not be combined with the `ReplacePath` rule type or any other annotation leveraging that rule type.
Trying to do so leads to an error and the corresponding Ingress object being ignored.
This annotation may not be combined with other redirect annotations.
Trying to do so will result in the other redirects being ignored.
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
<5> `traefik.ingress.kubernetes.io/service-weights`:
Service weights enable to split traffic across multiple backing services in a fine-grained manner.
Example:
```yaml
service_backend1: 12.50%
service_backend2: 12.50%
service_backend3: 75 # Same as 75%, the percentage sign is optional
```
A single service backend definition may be omitted; in this case, Traefik auto-completes that service backend to 100% automatically.
Conveniently, users need not bother to compute the percentage remainder for a main service backend.
For instance, in the example above `service_backend3` does not need to be specified to be assigned 75%.
!!! note
For each service weight given, the Ingress specification must include a backend item with the corresponding `serviceName` and (if given) matching path.
Currently, 3 decimal places for the weight are supported.
An attempt to exceed the precision should be avoided as it may lead to percentage computation flaws and, in consequence, Ingress parsing errors.
For each path definition, this annotation will fail if:
- the sum of backend weights exceeds 100% or
- the sum of backend weights is less than 100% without one or more omitted backends
See also the [user guide section traffic splitting](/user-guide/kubernetes/#traffic-splitting).
<6> `traefik.ingress.kubernetes.io/whitelist-source-range`:
All source IPs are permitted if the list is empty or a single range is ill-formatted.
Please note, you may have to set `service.spec.externalTrafficPolicy` to the value `Local` to preserve the source IP of the request for filtering.
Please see [this link](https://kubernetes.io/docs/tutorials/services/source-ip/) for more information.
!!! note
Please note that `traefik.ingress.kubernetes.io/redirect-regex` and `traefik.ingress.kubernetes.io/redirect-replacement` do not have to be set if `traefik.ingress.kubernetes.io/redirect-entry-point` is defined for the redirection (they will not be used in this case).
@@ -218,38 +275,77 @@ The following security annotations are applicable on the Ingress object:
| Annotation | Description |
| ----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `ingress.kubernetes.io/allowed-hosts: EXPR` | Provides a list of allowed hosts that requests will be processed. Format: `Host1,Host2` |
| `ingress.kubernetes.io/proxy-headers: EXPR` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
| `ingress.kubernetes.io/ssl-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `ingress.kubernetes.io/ssl-temporary-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `ingress.kubernetes.io/ssl-host: HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `ingress.kubernetes.io/ssl-proxy-headers: EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `ingress.kubernetes.io/browser-xss-filter: "true"` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `ingress.kubernetes.io/content-security-policy: VALUE` | Adds CSP Header with the custom value. |
| `ingress.kubernetes.io/content-type-nosniff: "true"` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `ingress.kubernetes.io/custom-browser-xss-value: VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `ingress.kubernetes.io/custom-frame-options-value: VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `ingress.kubernetes.io/force-hsts: "false"` | Adds the STS header to non-SSL requests. |
| `ingress.kubernetes.io/frame-deny: "false"` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `ingress.kubernetes.io/hsts-max-age: "315360000"` | Sets the max-age of the HSTS header. |
| `ingress.kubernetes.io/hsts-include-subdomains: "true"` | Adds the IncludeSubdomains section of the STS header. |
| `ingress.kubernetes.io/hsts-preload: "true"` | Adds the preload flag to the HSTS header. |
| `ingress.kubernetes.io/force-hsts: "false"` | Adds the STS header to non-SSL requests. |
| `ingress.kubernetes.io/frame-deny: "false"` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `ingress.kubernetes.io/custom-frame-options-value: VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `ingress.kubernetes.io/content-type-nosniff: "true"` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `ingress.kubernetes.io/browser-xss-filter: "true"` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `ingress.kubernetes.io/custom-browser-xss-value: VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `ingress.kubernetes.io/content-security-policy: VALUE` | Adds CSP Header with the custom value. |
| `ingress.kubernetes.io/is-development: "false"` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `ingress.kubernetes.io/proxy-headers: EXPR` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
| `ingress.kubernetes.io/public-key: VALUE` | Adds pinned HTST public key header. |
| `ingress.kubernetes.io/referrer-policy: VALUE` | Adds referrer policy header. |
| `ingress.kubernetes.io/is-development: "false"` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `ingress.kubernetes.io/ssl-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `ingress.kubernetes.io/ssl-temporary-redirect: "true"` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `ingress.kubernetes.io/ssl-host: HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `ingress.kubernetes.io/ssl-force-host: "true"` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `ingress.kubernetes.io/ssl-proxy-headers: EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
### Authentication
Is possible to add additional authentication annotations to the Ingress object.
Additional authentication annotations can be added to the Ingress object.
The source of the authentication is a Secret object that contains the credentials.
| Annotation | Description |
|-----------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| `ingress.kubernetes.io/auth-type: basic` | Contains the authentication type. The only permitted type is `basic`. |
| `ingress.kubernetes.io/auth-secret: mysecret` | Name of Secret containing the username and password with access to the paths defined in the Ingress object. |
| Annotation | basic | digest | forward | Description |
|----------------------------------------------------------------------|-------|--------|---------|-------------------------------------------------------------------------------------------------------------|
| `ingress.kubernetes.io/auth-type: basic` | x | x | x | Contains the authentication type: `basic`, `digest`, `forward`. |
| `ingress.kubernetes.io/auth-secret: mysecret` | x | x | | Name of Secret containing the username and password with access to the paths defined in the Ingress object. |
| `ingress.kubernetes.io/auth-remove-header: true` | x | x | | If set to `true` removes the `Authorization` header. |
| `ingress.kubernetes.io/auth-header-field: X-WebAuth-User` | x | x | | Pass Authenticated user to application via headers. |
| `ingress.kubernetes.io/auth-url: https://example.com` | | | x | [The URL of the authentication server](/configuration/entrypoints/#forward-authentication). |
| `ingress.kubernetes.io/auth-trust-headers: false` | | | x | Trust `X-Forwarded-*` headers. |
| `ingress.kubernetes.io/auth-response-headers: X-Auth-User, X-Secret` | | | x | Copy headers from the authentication server to the request. |
| `ingress.kubernetes.io/auth-tls-secret: secret` | | | x | Name of Secret containing the certificate and key for the forward auth. |
| `ingress.kubernetes.io/auth-tls-insecure` | | | x | If set to `true` invalid SSL certificates are accepted. |
The secret must be created in the same namespace as the Ingress object.
The following limitations hold:
The following limitations hold for basic/digest auth:
- The realm is not configurable; the only supported (and default) value is `traefik`.
- The Secret must contain a single file only.
### TLS certificates management
TLS certificates can be managed in Secrets objects.
More information are available in the [User Guide](/user-guide/kubernetes/#add-a-tls-certificate-to-the-ingress).
!!! note
Only TLS certificates provided by users can be stored in Kubernetes Secrets.
[Let's Encrypt](https://letsencrypt.org) certificates cannot be managed in Kubernets Secrets yet.
### Global Default Backend Ingresses
Ingresses can be created that look like the following:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheese
spec:
backend:
serviceName: stilton
servicePort: 80
```
This ingress follows the [Global Default Backend](https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource) property of ingresses.
This will allow users to create a "default backend" that will match all unmatched requests.
!!! note
Due to Træfik's use of priorities, you may have to set this ingress priority lower than other ingresses in your environment, to avoid this global ingress from satisfying requests that _could_ match other ingresses.
To do this, use the `traefik.ingress.kubernetes.io/priority` annotation (as seen in [General Annotations](/configuration/backends/kubernetes/#general-annotations)) on your ingresses accordingly.

View File

@@ -1,6 +1,6 @@
# Marathon Backend
# Marathon Provider
Træfik can be configured to use Marathon as a backend configuration.
Træfik can be configured to use Marathon as a provider.
See also [Marathon user guide](/user-guide/marathon).
@@ -9,10 +9,10 @@ See also [Marathon user guide](/user-guide/marathon).
```toml
################################################################
# Mesos/Marathon configuration backend
# Mesos/Marathon Provider
################################################################
# Enable Marathon configuration backend.
# Enable Marathon Provider.
[marathon]
# Marathon server endpoint.
@@ -52,7 +52,7 @@ domain = "marathon.localhost"
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = "2"
# templateVersion = 2
# Expose Marathon apps by default in Traefik.
#
@@ -103,7 +103,7 @@ domain = "marathon.localhost"
# CA = "/etc/ssl/ca.crt"
# Cert = "/etc/ssl/marathon.cert"
# Key = "/etc/ssl/marathon.key"
# InsecureSkipVerify = true
# insecureSkipVerify = true
# DCOSToken for DCOS environment.
# This will override the Authorization header.
@@ -120,9 +120,33 @@ domain = "marathon.localhost"
# If no units are provided, the value is parsed assuming seconds.
#
# Optional
# Default: "5s"
#
# dialerTimeout = "5s"
# Override ResponseHeaderTimeout.
# Amount of time to allow the Marathon provider to wait until the first response
# header from the Marathon master is received.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits).
# If no units are provided, the value is parsed assuming seconds.
#
# Optional
# Default: "60s"
#
# dialerTimeout = "60s"
# responseHeaderTimeout = "60s"
# Override TLSHandshakeTimeout.
# Amount of time to allow the Marathon provider to wait until the TLS
# handshake completes.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits).
# If no units are provided, the value is parsed assuming seconds.
#
# Optional
# Default: "5s"
#
# TLSHandshakeTimeout = "5s"
# Set the TCP Keep Alive interval for the Marathon HTTP Client.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
@@ -157,7 +181,7 @@ domain = "marathon.localhost"
# respectReadinessChecks = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Labels: overriding default behavior
@@ -169,48 +193,67 @@ They may be specified on one of two levels: Application or service.
The following labels can be defined on Marathon applications. They adjust the behavior for the entire application.
| Label | Description |
|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
| `traefik.portIndex=1` | Register port by index in the application's ports array. Useful when the application exposes multiple ports. |
| `traefik.protocol=https` | Override the default `http` protocol |
| `traefik.weight=10` | Assign this weight to the container |
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. (Default: 30s) |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Override default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{sub_domain}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.domain` | Sets the default domain used for the frontend rules. |
| `traefik.enable=false` | Disables this container in Træfik. |
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
| `traefik.protocol=https` | Overrides the default `http` protocol. |
| `traefik.weight=10` | Assigns this weight to the container. |
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Overrides default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{sub_domain}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
#### Custom Headers
@@ -225,24 +268,25 @@ The following labels can be defined on Marathon applications. They adjust the be
| Label | Description |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
### Applications with Multiple Ports (segment labels)
@@ -252,61 +296,77 @@ You can define as many segments as ports exposed in an application.
Segment labels override the default behavior.
| Label | Description |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.portIndex=1` | Create a service binding with frontend/backend using this port index. Overrides `traefik.portIndex`. |
| `traefik.<segment_name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the service labels could be used. |
| `traefik.<segment_name>.protocol=http` | Overrides `traefik.protocol`. |
| `traefik.<segment_name>.weight=10` | Assign this service weight. Overrides `traefik.weight`. |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Sets a Basic Auth for that frontend |
| `traefik.<segment_name>.frontend.backend=BACKEND` | Assign this service frontend to `BACKEND`. Default is to assign to the service backend. |
| `traefik.<segment_name>.frontend.entryPoints=https` | Overrides `traefik.frontend.entrypoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Overrides `traefik.frontend.passHostHeader`. |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Overrides `traefik.frontend.passTLSCert`. |
| `traefik.<segment_name>.frontend.priority=10` | Overrides `traefik.frontend.priority`. |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Overrides `traefik.frontend.redirect.entryPoint`. |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Overrides `traefik.frontend.redirect.regex`. |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Overrides `traefik.frontend.redirect.replacement`. |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.<segment_name>.frontend.rule=EXP` | Overrides `traefik.frontend.rule`. Default: `{service_name}.{sub_domain}.{domain}` |
| `traefik.<segment_name>.frontend.whitelistSourceRange=RANGE` | Overrides `traefik.frontend.whitelistSourceRange`. |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Overrides `traefik.frontend.whiteList.sourceRange`. |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|---------------------------------------------------------------------------|----------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
#### Custom Headers
| Label | Description |
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container.<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client.<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| Label | Description |
|----------------------------------------------------------------------|----------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | Same as `traefik.frontend.headers.customRequestHeaders` |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | Same as `traefik.frontend.headers.customResponseHeaders` |
#### Security Headers
| Label | Description |
|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| Label | Description |
|-------------------------------------------------------------------------|--------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | Same as `traefik.frontend.headers.allowedHosts` |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | Same as `traefik.frontend.headers.browserXSSFilter` |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | Same as `traefik.frontend.headers.contentSecurityPolicy` |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | Same as `traefik.frontend.headers.contentTypeNosniff` |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | Same as `traefik.frontend.headers.customBrowserXSSValue` |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | Same as `traefik.frontend.headers.customFrameOptionsValue` |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | Same as `traefik.frontend.headers.forceSTSHeader` |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | Same as `traefik.frontend.headers.frameDeny` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR` | Same as `traefik.frontend.headers.hostsProxyHeaders` |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | Same as `traefik.frontend.headers.isDevelopment` |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | Same as `traefik.frontend.headers.publicKey` |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | Same as `traefik.frontend.headers.referrerPolicy` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | Same as `traefik.frontend.headers.SSLRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | Same as `traefik.frontend.headers.SSLTemporaryRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | Same as `traefik.frontend.headers.SSLHost` |
| `traefik.<segment_name>.frontend.headers.SSLForceHost=true` | Same as `traefik.frontend.headers.SSLForceHost` |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | Same as `traefik.frontend.headers.SSLProxyHeaders=EXPR` |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | Same as `traefik.frontend.headers.STSSeconds=315360000` |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | Same as `traefik.frontend.headers.STSIncludeSubdomains=true` |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | Same as `traefik.frontend.headers.STSPreload=true` |

View File

@@ -1,13 +1,13 @@
# Mesos Generic Backend
# Mesos Generic Provider
Træfik can be configured to use Mesos as a backend configuration.
Træfik can be configured to use Mesos as a provider.
```toml
################################################################
# Mesos configuration backend
# Mesos Provider
################################################################
# Enable Mesos configuration backend.
# Enable Mesos Provider.
[mesos]
# Mesos server endpoint.
@@ -34,6 +34,13 @@ watch = true
#
domain = "mesos.localhost"
# Expose Mesos apps by default in Traefik.
#
# Optional
# Default: true
#
# exposedByDefault = false
# Override default configuration template.
# For advanced users :)
#
@@ -41,46 +48,48 @@ domain = "mesos.localhost"
#
# filename = "mesos.tmpl"
# Expose Mesos apps by default in Traefik.
# Override template version
# For advanced users :)
#
# Optional
# Default: true
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# ExposedByDefault = false
# templateVersion = 2
# TLS client configuration. https://golang.org/pkg/crypto/tls/#Config
#
# Optional
#
# [mesos.TLS]
# InsecureSkipVerify = true
# insecureSkipVerify = true
# Zookeeper timeout (in seconds).
#
# Optional
# Default: 30
#
# ZkDetectionTimeout = 30
# zkDetectionTimeout = 30
# Polling interval (in seconds).
#
# Optional
# Default: 30
#
# RefreshSeconds = 30
# refreshSeconds = 30
# IP sources (e.g. host, docker, mesos, netinfo).
#
# Optional
#
# IPSources = "host"
# ipSources = "host"
# HTTP Timeout (in seconds).
#
# Optional
# Default: 30
#
# StateTimeoutSecond = "30"
# stateTimeoutSecond = "30"
# Convert groups to subdomains.
# Default behavior: /foo/bar/myapp => foo-bar-myapp.{defaultDomain}
@@ -90,53 +99,74 @@ domain = "mesos.localhost"
# Default: false
#
# groupsAsSubDomains = true
```
## Labels: overriding default behaviour
## Labels: overriding default behavior
The following labels can be defined on Mesos tasks. They adjust the behaviour for the entire application.
The following labels can be defined on Mesos tasks. They adjust the behavior for the entire application.
| Label | Description |
|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
| `traefik.portIndex=1` | Register port by index in the application's ports array. Useful when the application exposes multiple ports. |
| `traefik.protocol=https` | Override the default `http` protocol |
| `traefik.weight=10` | Assign this weight to the container |
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. (Default: 30s) |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Override default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{discovery_name}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.domain` | Sets the default domain for the frontend rules. |
| `traefik.enable=false` | Disables this container in Træfik. |
| `traefik.port=80` | Registers this port. Useful when the application exposes multiple ports. |
| `traefik.portName=web` | Registers port by name in the application's ports array. Useful when the application exposes multiple ports. |
| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. |
| `traefik.protocol=https` | Overrides the default `http` protocol |
| `traefik.weight=10` | Assigns this weight to the container |
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie manually name for sticky sessions |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Overrides default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{discovery_name}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
### Custom Headers
@@ -150,21 +180,108 @@ The following labels can be defined on Mesos tasks. They adjust the behaviour fo
| Label | Description |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
### Applications with Multiple Ports (segment labels)
Segment labels are used to define routes to an application exposing multiple ports.
A segment is a group of labels that apply to a port exposed by an application.
You can define as many segments as ports exposed in an application.
Additionally, if a segment name matches a named port, that port will be used unless `portIndex`, `portName`, or `port` labels are specified for that segment.
Segment labels override the default behavior.
| Label | Description |
|---------------------------------------------------------------------------|----------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
| `traefik.<segment_name>.portName=web` | Same as `traefik.portName` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
#### Custom Headers
| Label | Description |
|----------------------------------------------------------------------|----------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | Same as `traefik.frontend.headers.customRequestHeaders` |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | Same as `traefik.frontend.headers.customResponseHeaders` |
#### Security Headers
| Label | Description |
|-------------------------------------------------------------------------|--------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | Same as `traefik.frontend.headers.allowedHosts` |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | Same as `traefik.frontend.headers.browserXSSFilter` |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | Same as `traefik.frontend.headers.contentSecurityPolicy` |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | Same as `traefik.frontend.headers.contentTypeNosniff` |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | Same as `traefik.frontend.headers.customBrowserXSSValue` |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | Same as `traefik.frontend.headers.customFrameOptionsValue` |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | Same as `traefik.frontend.headers.forceSTSHeader` |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | Same as `traefik.frontend.headers.frameDeny` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR` | Same as `traefik.frontend.headers.hostsProxyHeaders` |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | Same as `traefik.frontend.headers.isDevelopment` |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | Same as `traefik.frontend.headers.publicKey` |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | Same as `traefik.frontend.headers.referrerPolicy` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | Same as `traefik.frontend.headers.SSLRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | Same as `traefik.frontend.headers.SSLTemporaryRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | Same as `traefik.frontend.headers.SSLHost` |
| `traefik.<segment_name>.frontend.headers.SSLForceHost=true` | Same as `traefik.frontend.headers.SSLForceHost` |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | Same as `traefik.frontend.headers.SSLProxyHeaders=EXPR` |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | Same as `traefik.frontend.headers.STSSeconds=315360000` |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | Same as `traefik.frontend.headers.STSIncludeSubdomains=true` |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | Same as `traefik.frontend.headers.STSPreload=true` |

View File

@@ -1,15 +1,15 @@
# Rancher Backend
# Rancher Provider
Træfik can be configured to use Rancher as a backend configuration.
Træfik can be configured to use Rancher as a provider.
## Global Configuration
```toml
################################################################
# Rancher configuration backend
# Rancher Provider
################################################################
# Enable Rancher configuration backend.
# Enable Rancher Provider.
[rancher]
# Default domain used.
@@ -61,23 +61,23 @@ enableServiceHealthFilter = true
# - "1": previous template version (must be used only with older custom templates, see "filename")
# - "2": current template version (must be used to force template version when "filename" is used)
#
# templateVersion = "2"
# templateVersion = 2
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
## Rancher Metadata Service
```toml
# Enable Rancher metadata service configuration backend instead of the API
# configuration backend.
# Enable Rancher metadata service provider instead of the API
# provider.
#
# Optional
# Default: false
#
[rancher.metadata]
# Poll the Rancher metadata service for changes every `rancher.RefreshSeconds`.
# Poll the Rancher metadata service for changes every `rancher.refreshSeconds`.
# NOTE: this is less accurate than the default long polling technique which
# will provide near instantaneous updates to Traefik
#
@@ -97,7 +97,7 @@ prefix = "/2016-07-29"
## Rancher API
```toml
# Enable Rancher API configuration backend.
# Enable Rancher API provider.
#
# Optional
# Default: true
@@ -138,47 +138,65 @@ secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Labels can be used on task containers to override default behavior:
| Label | Description |
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
| `traefik.protocol=https` | Override the default `http` protocol |
| `traefik.weight=10` | Assign this weight to the container |
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forward TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Override default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{service_name}.{stack_name}.{domain}`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | List of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| Label | Description |
|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.domain` | Sets the default domain for the frontend rules. |
| `traefik.enable=false` | Disables this container in Træfik. |
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
| `traefik.protocol=https` | Overrides the default `http` protocol. |
| `traefik.weight=10` | Assigns this weight to the container. |
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` . |
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. |
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `traefik.frontend.priority=10` | Overrides default frontend priority |
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. |
| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. |
#### Custom Headers
@@ -192,24 +210,25 @@ Labels can be used on task containers to override default behavior:
| Label | Description |
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed.<br>Format: `Host1,Host2` |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.<br>Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. |
| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. |
| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. |
| `traefik.frontend.headers.SSLForceHost=true` | If `SSLForceHost` is `true` and `SSLHost` is set, requests will be forced to use `SSLHost` even the ones that are already using SSL. Default is false. |
| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`).<br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. |
| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. |
| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. |
| `traefik.frontend.headers.customBrowserXSSValue=VALUE` | Set custom value for X-XSS-Protection header. This overrides the BrowserXssFilter option. |
| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.<br>When deploying to production, be sure to set this to false. |
### On containers with Multiple Ports (segment labels)
@@ -219,59 +238,75 @@ You can define as many segments as ports exposed in a container.
Segment labels override the default behavior.
| Label | Description |
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| `traefik.<segment_name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the segment labels could be used. |
| `traefik.<segment_name>.protocol` | Overrides `traefik.protocol`. |
| `traefik.<segment_name>.weight` | Assign this segment weight. Overrides `traefik.weight`. |
| `traefik.<segment_name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
| `traefik.<segment_name>.frontend.backend=BACKEND` | Assign this segment frontend to `BACKEND`. Default is to assign to the segment backend. |
| `traefik.<segment_name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.<segment_name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
| `traefik.<segment_name>.frontend.passTLSCert` | Overrides `traefik.frontend.passTLSCert`. |
| `traefik.<segment_name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Overrides `traefik.frontend.redirect.entryPoint`. |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Overrides `traefik.frontend.redirect.regex`. |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Overrides `traefik.frontend.redirect.replacement`. |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Return 301 instead of 302. |
| `traefik.<segment_name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Overrides `traefik.frontend.whiteList.sourceRange`. |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Overrides `traefik.frontend.whiteList.useXForwardedFor`. |
| Label | Description |
|---------------------------------------------------------------------------|---------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersfile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersfile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersfile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersfile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify`|
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
#### Custom Headers
| Label | Description |
|----------------------------------------------------------------------|-----------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | overrides `traefik.frontend.headers.customRequestHeaders=EXPR ` |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | overrides `traefik.frontend.headers.customResponseHeaders=EXPR` |
| Label | Description |
|----------------------------------------------------------------------|------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.customRequestHeaders=EXPR ` | overrides `traefik.frontend.headers.customRequestHeaders` |
| `traefik.<segment_name>.frontend.headers.customResponseHeaders=EXPR` | overrides `traefik.frontend.headers.customResponseHeaders` |
#### Security Headers
| Label | Description |
|-------------------------------------------------------------------------|--------------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | overrides `traefik.frontend.headers.allowedHosts=EXPR` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR` | overrides `traefik.frontend.headers.hostsProxyHeaders=EXPR` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | overrides `traefik.frontend.headers.SSLRedirect=true` |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | overrides `traefik.frontend.headers.SSLTemporaryRedirect=true` |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | overrides `traefik.frontend.headers.SSLHost=HOST` |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | overrides `traefik.frontend.headers.SSLProxyHeaders=EXPR` |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | overrides `traefik.frontend.headers.STSSeconds=315360000` |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | overrides `traefik.frontend.headers.STSIncludeSubdomains=true` |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | overrides `traefik.frontend.headers.STSPreload=true` |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | overrides `traefik.frontend.headers.forceSTSHeader=false` |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | overrides `traefik.frontend.headers.frameDeny=false` |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | overrides `traefik.frontend.headers.customFrameOptionsValue=VALUE` |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | overrides `traefik.frontend.headers.contentTypeNosniff=true` |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | overrides `traefik.frontend.headers.browserXSSFilter=true` |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | overrides `traefik.frontend.headers.customBrowserXSSValue=VALUE` |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | overrides `traefik.frontend.headers.contentSecurityPolicy=VALUE` |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | overrides `traefik.frontend.headers.publicKey=VALUE` |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | overrides `traefik.frontend.headers.referrerPolicy=VALUE` |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | overrides `traefik.frontend.headers.isDevelopment=false` |
| Label | Description |
|-------------------------------------------------------------------------|--------------------------------------------------------------|
| `traefik.<segment_name>.frontend.headers.allowedHosts=EXPR` | overrides `traefik.frontend.headers.allowedHosts` |
| `traefik.<segment_name>.frontend.headers.browserXSSFilter=true` | overrides `traefik.frontend.headers.browserXSSFilter` |
| `traefik.<segment_name>.frontend.headers.contentSecurityPolicy=VALUE` | overrides `traefik.frontend.headers.contentSecurityPolicy` |
| `traefik.<segment_name>.frontend.headers.contentTypeNosniff=true` | overrides `traefik.frontend.headers.contentTypeNosniff` |
| `traefik.<segment_name>.frontend.headers.customBrowserXSSValue=VALUE` | overrides `traefik.frontend.headers.customBrowserXSSValue` |
| `traefik.<segment_name>.frontend.headers.customFrameOptionsValue=VALUE` | overrides `traefik.frontend.headers.customFrameOptionsValue` |
| `traefik.<segment_name>.frontend.headers.forceSTSHeader=false` | overrides `traefik.frontend.headers.forceSTSHeader` |
| `traefik.<segment_name>.frontend.headers.frameDeny=false` | overrides `traefik.frontend.headers.frameDeny` |
| `traefik.<segment_name>.frontend.headers.hostsProxyHeaders=EXPR` | overrides `traefik.frontend.headers.hostsProxyHeaders` |
| `traefik.<segment_name>.frontend.headers.isDevelopment=false` | overrides `traefik.frontend.headers.isDevelopment` |
| `traefik.<segment_name>.frontend.headers.publicKey=VALUE` | overrides `traefik.frontend.headers.publicKey` |
| `traefik.<segment_name>.frontend.headers.referrerPolicy=VALUE` | overrides `traefik.frontend.headers.referrerPolicy` |
| `traefik.<segment_name>.frontend.headers.SSLRedirect=true` | overrides `traefik.frontend.headers.SSLRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLTemporaryRedirect=true` | overrides `traefik.frontend.headers.SSLTemporaryRedirect` |
| `traefik.<segment_name>.frontend.headers.SSLHost=HOST` | overrides `traefik.frontend.headers.SSLHost` |
| `traefik.<segment_name>.frontend.headers.SSLForceHost=true` | overrides `traefik.frontend.headers.SSLForceHost` |
| `traefik.<segment_name>.frontend.headers.SSLProxyHeaders=EXPR` | overrides `traefik.frontend.headers.SSLProxyHeaders` |
| `traefik.<segment_name>.frontend.headers.STSSeconds=315360000` | overrides `traefik.frontend.headers.STSSeconds` |
| `traefik.<segment_name>.frontend.headers.STSIncludeSubdomains=true` | overrides `traefik.frontend.headers.STSIncludeSubdomains` |
| `traefik.<segment_name>.frontend.headers.STSPreload=true` | overrides `traefik.frontend.headers.STSPreload` |

View File

@@ -1,4 +1,4 @@
# Rest Backend
# Rest Provider
Træfik can be configured:
@@ -7,7 +7,7 @@ Træfik can be configured:
## Configuration
```toml
# Enable rest backend.
# Enable REST Provider.
[rest]
# Name of the related entry point
#

View File

@@ -1,33 +1,33 @@
# Service Fabric Backend
# Azure Service Fabric Provider
Træfik can be configured to use Service Fabric as a backend configuration.
Træfik can be configured to use Azure Service Fabric as a provider.
See [this repository for an example deployment package and further documentation.](https://aka.ms/traefikonsf)
## Service Fabric
## Azure Service Fabric
```toml
################################################################
# Service Fabric provider
# Azure Service Fabric Provider
################################################################
# Enable Service Fabric configuration backend
# Enable Azure Service Fabric Provider
[serviceFabric]
# Service Fabric Management Endpoint
# Azure Service Fabric Management Endpoint
#
# Required
#
clusterManagementUrl = "https://localhost:19080"
# Service Fabric Management Endpoint API Version
# Azure Service Fabric Management Endpoint API Version
#
# Required
# Default: "3.0"
#
apiVersion = "3.0"
# Service Fabric Polling Interval (in seconds)
# Azure Service Fabric Polling Interval (in seconds)
#
# Required
# Default: 10
@@ -42,7 +42,7 @@ refreshSeconds = 10
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/servicefabric.crt"
# key = "/etc/ssl/servicefabric.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
## Labels
@@ -61,7 +61,7 @@ Here is an example of an extension setting Træfik labels:
<Extension Name="Traefik">
<Labels xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
<Label Key="traefik.frontend.rule.example2">PathPrefixStrip: /a/path/to/strip</Label>
<Label Key="traefik.expose">true</Label>
<Label Key="traefik.enable">true</Label>
<Label Key="traefik.frontend.passHostHeader">true</Label>
</Labels>
</Extension>
@@ -98,11 +98,14 @@ Labels, set through extensions or the property manager, can be used on services
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.enable=false` | Disable this container in Træfik |
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.group.name` | Group all services with the same name into a single backend in Træfik |
| `traefik.backend.group.weight` | Set the weighting of the current services nodes in the backend group |
| `traefik.servicefabric.groupname` | Group all services with the same name into a single backend in Træfik |
| `traefik.servicefabric.groupweight` | Set the weighting of the current services nodes in the backend group |
| `traefik.servicefabric.enablelabeloverrides` | Toggle whether labels can be overridden using the Service Fabric Property Manager API |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Define the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Define the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |

View File

@@ -1,4 +1,4 @@
# Web Backend
# Web Provider
!!! danger "DEPRECATED"
The web provider is deprecated, please use the [api](/configuration/api.md), the [ping](/configuration/ping.md), the [metrics](/configuration/metrics) and the [rest](/configuration/backends/rest.md) provider.
@@ -12,7 +12,7 @@ Træfik can be configured:
## Configuration
```toml
# Enable web backend.
# Enable Web Provider.
[web]
# Web administration port.
@@ -185,6 +185,13 @@ pushinterval = "10s"
#
address = "localhost:8089"
# InfluxDB's address protocol (udp or http)
#
# Required
# Default: "udp"
#
protocol = "udp"
# InfluxDB push interval
#
# Optional
@@ -192,6 +199,20 @@ address = "localhost:8089"
#
pushinterval = "10s"
# InfluxDB database used when protocol is http
#
# Optional
# Default: ""
#
database = ""
# InfluxDB retention policy used when protocol is http
#
# Optional
# Default: ""
#
retentionpolicy = ""
# ...
```

View File

@@ -1,13 +1,13 @@
# Zookeeper Backend
# Zookeeper Provider
Træfik can be configured to use Zookeeper as a backend configuration.
Træfik can be configured to use Zookeeper as a provider.
```toml
################################################################
# Zookeeper configuration backend
# Zookeeper Provider
################################################################
# Enable Zookeeperconfiguration backend.
# Enable Zookeeper Provider.
[zookeeper]
# Zookeeper server endpoint.
@@ -53,9 +53,9 @@ prefix = "traefik"
# ca = "/etc/ssl/ca.crt"
# cert = "/etc/ssl/zookeeper.crt"
# key = "/etc/ssl/zookeeper.key"
# insecureskipverify = true
# insecureSkipVerify = true
```
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
Please refer to the [Key Value storage structure](/user-guide/kv-config/#key-value-storage-structure) section to get documentation on Traefik KV structure.

View File

@@ -18,7 +18,7 @@
# Enable debug mode.
# This will install HTTP handlers to expose Go expvars under /debug/vars and
# pprof profiling data under /debug/pprof.
# pprof profiling data under /debug/pprof/.
# The log level will be set to DEBUG unless `logLevel` is specified.
#
# Optional
@@ -33,19 +33,19 @@
#
# checkNewVersion = false
# Backends throttle duration.
# Providers throttle duration.
#
# Optional
# Default: "2s"
#
# ProvidersThrottleDuration = "2s"
# providersThrottleDuration = "2s"
# Controls the maximum idle (keep-alive) connections to keep per-host.
#
# Optional
# Default: 200
#
# MaxIdleConnsPerHost = 200
# maxIdleConnsPerHost = 200
# If set to true invalid SSL certificates are accepted for backends.
# This disables detection of man-in-the-middle attacks so should only be used on secure backend networks.
@@ -53,14 +53,14 @@
# Optional
# Default: false
#
# InsecureSkipVerify = true
# insecureSkipVerify = true
# Register Certificates in the RootCA.
# Register Certificates in the rootCA.
#
# Optional
# Default: []
#
# RootCAs = [ "/mycert.cert" ]
# rootCAs = [ "/mycert.cert" ]
# Entrypoints to be used by frontends that do not specify any entrypoint.
# Each frontend can specify its own entrypoints.
@@ -69,6 +69,15 @@
# Default: ["http"]
#
# defaultEntryPoints = ["http", "https"]
# Allow the use of 0 as server weight.
# - false: a weight 0 means internally a weight of 1.
# - true: a weight 0 means internally a weight of 0 (a server with a weight of 0 is removed from the available servers).
#
# Optional
# Default: false
#
# AllowMinWeightZero = true
```
- `graceTimeOut`: Duration to give active requests a chance to finish before Traefik stops.
@@ -76,19 +85,19 @@ Can be provided in a format supported by [time.ParseDuration](https://golang.org
If no units are provided, the value is parsed assuming seconds.
**Note:** in this time frame no new requests are accepted.
- `ProvidersThrottleDuration`: Backends throttle duration: minimum duration in seconds between 2 events from providers before applying a new configuration.
- `providersThrottleDuration`: Providers throttle duration: minimum duration in seconds between 2 events from providers before applying a new configuration.
It avoids unnecessary reloads if multiples events are sent in a short amount of time.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
If no units are provided, the value is parsed assuming seconds.
- `MaxIdleConnsPerHost`: Controls the maximum idle (keep-alive) connections to keep per-host.
- `maxIdleConnsPerHost`: Controls the maximum idle (keep-alive) connections to keep per-host.
If zero, `DefaultMaxIdleConnsPerHost` from the Go standard library net/http module is used.
If you encounter 'too many open files' errors, you can either increase this value or change the `ulimit`.
- `InsecureSkipVerify` : If set to true invalid SSL certificates are accepted for backends.
- `insecureSkipVerify` : If set to true invalid SSL certificates are accepted for backends.
**Note:** This disables detection of man-in-the-middle attacks so should only be used on secure backend networks.
- `RootCAs`: Register Certificates in the RootCA. This certificates will be use for backends calls.
- `rootCAs`: Register Certificates in the RootCA. This certificates will be use for backends calls.
**Note** You can use file path or cert content directly
- `defaultEntryPoints`: Entrypoints to be used by frontends that do not specify any entrypoint.
@@ -99,7 +108,7 @@ Each frontend can specify its own entrypoints.
In a micro-service architecture, with a central service discovery, setting constraints limits Træfik scope to a smaller number of routes.
Træfik filters services according to service attributes/tags set in your configuration backends.
Træfik filters services according to service attributes/tags set in your providers.
Supported filters:
@@ -127,14 +136,15 @@ constraints = ["tag==us-*"]
constraints = ["tag!=us-*", "tag!=asia-*"]
```
### Backend-specific
### provider-specific
Supported backends:
Supported Providers:
- Docker
- Consul K/V
- BoltDB
- Zookeeper
- ECS
- Etcd
- Consul Catalog
- Rancher
@@ -142,12 +152,12 @@ Supported backends:
- Kubernetes (using a provider-specific mechanism based on label selectors)
```toml
# Backend-specific constraint
# Provider-specific constraint
[consulCatalog]
# ...
constraints = ["tag==api"]
# Backend-specific constraint
# Provider-specific constraint
[marathon]
# ...
constraints = ["tag==api", "tag!=v*-beta"]
@@ -386,38 +396,70 @@ If no units are provided, the value is parsed assuming seconds.
### Idle Timeout (deprecated)
Use [respondingTimeouts](/configuration/commons/#responding-timeouts) instead of `IdleTimeout`.
Use [respondingTimeouts](/configuration/commons/#responding-timeouts) instead of `idleTimeout`.
In the case both settings are configured, the deprecated option will be overwritten.
`IdleTimeout` is the maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.
`idleTimeout` is the maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.
This is set to enforce closing of stale client connections.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
If no units are provided, the value is parsed assuming seconds.
```toml
# IdleTimeout
# idleTimeout
#
# DEPRECATED - see [respondingTimeouts] section.
#
# Optional
# Default: "180s"
#
IdleTimeout = "360s"
idleTimeout = "360s"
```
## Host Resolver
`hostResolver` are used for request host matching process.
```toml
[hostResolver]
# cnameFlattening is a trigger to flatten request host, assuming it is a CNAME record
#
# Optional
# Default : false
#
cnameFlattening = true
# resolvConf is dns resolving configuration file, the default is /etc/resolv.conf
#
# Optional
# Default : "/etc/resolv.conf"
#
# resolvConf = "/etc/resolv.conf"
# resolvDepth is the maximum CNAME recursive lookup
#
# Optional
# Default : 5
#
# resolvDepth = 5
```
- To allow serving secure https request and generate the SSL using ACME while `cnameFlattening` is active.
The `acme` configuration for `HTTP-01` challenge and `onDemand` is mandatory.
Refer to [ACME configuration](/configuration/acme) for more information.
## Override Default Configuration Template
!!! warning
For advanced users only.
Supported by all backends except: File backend, Web backend and DynamoDB backend.
Supported by all providers except: File Provider, Web Provider and DynamoDB Provider.
```toml
[backend_name]
[provider_name]
# Override default configuration template. For advanced users :)
# Override default provider configuration template. For advanced users :)
#
# Optional
# Default: ""

View File

@@ -5,6 +5,11 @@
### TOML
```toml
defaultEntryPoints = ["http", "https"]
# ...
# ...
[entryPoints]
[entryPoints.http]
address = ":80"
@@ -40,12 +45,14 @@
[entryPoints.http.auth]
headerField = "X-WebAuth-User"
[entryPoints.http.auth.basic]
removeHeader = true
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
usersFile = "/path/to/.htpasswd"
[entryPoints.http.auth.digest]
removeHeader = true
users = [
"test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
@@ -54,8 +61,9 @@
[entryPoints.http.auth.forward]
address = "https://authserver.com/auth"
trustForwardHeader = true
authResponseHeaders = ["X-Auth-User"]
[entryPoints.http.auth.forward.tls]
ca = [ "path/to/local.crt"]
ca = "path/to/local.crt"
caOptional = true
cert = "path/to/foo.cert"
key = "path/to/foo.key"
@@ -106,8 +114,13 @@ traefik:
```ini
Name:foo
Address::80
TLS:goo,gii
TLS:/my/path/foo.cert,/my/path/foo.key;/my/path/goo.cert,/my/path/goo.key;/my/path/hoo.cert,/my/path/hoo.key
TLS
TLS.MinVersion:VersionTLS11
TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384
TLS.SniStrict:true
TLS.DefaultCertificate.Cert:path/to/foo.cert
TLS.DefaultCertificate.Key:path/to/foo.key
CA:car
CA.Optional:true
Redirect.EntryPoint:https
@@ -118,12 +131,15 @@ Compress:true
WhiteList.SourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16
WhiteList.UseXForwardedFor:true
ProxyProtocol.TrustedIPs:192.168.0.1
ProxyProtocol.Insecure:tue
ProxyProtocol.Insecure:true
ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24
Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
Auth.Basic.Removeheader:true
Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e
Auth.Digest.Removeheader:true
Auth.HeaderField:X-WebAuth-User
Auth.Forward.Address:https://authserver.com/auth
Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret
Auth.Forward.TrustForwardHeader:true
Auth.Forward.TLS.CA:path/to/local.crt
Auth.Forward.TLS.CAOptional:true
@@ -208,7 +224,7 @@ Define an entrypoint with SNI support.
```
!!! note
If an empty TLS configuration is done, default self-signed certificates are generated.
If an empty TLS configuration is provided, default self-signed certificates are generated.
### Dynamic Certificates
@@ -268,6 +284,32 @@ Users can be specified directly in the TOML file, or indirectly by referencing a
usersFile = "/path/to/.htpasswd"
```
Optionally, you can:
- pass authenticated user to application via headers
```toml
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth]
headerField = "X-WebAuth-User" # <-- header for the authenticated user
[entryPoints.http.auth.basic]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
```
- remove the Authorization header
```toml
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth]
[entryPoints.http.auth.basic]
removeHeader = true # <-- remove the Authorization header
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
```
### Digest Authentication
You can use `htdigest` to generate them.
@@ -285,6 +327,32 @@ Users can be specified directly in the TOML file, or indirectly by referencing a
usersFile = "/path/to/.htdigest"
```
Optionally, you can!
- pass authenticated user to application via headers.
```toml
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth]
headerField = "X-WebAuth-User" # <-- header for the authenticated user
[entryPoints.http.auth.digest]
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
```
- remove the Authorization header.
```toml
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth]
[entryPoints.http.auth.digest]
removeHeader = true # <-- remove the Authorization header
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
```
### Forward Authentication
This configuration will first forward the request to `http://authserver.com/auth`.
@@ -308,13 +376,21 @@ Otherwise, the response from the authentication server is returned.
#
trustForwardHeader = true
# Enable forward auth TLS connection.
# Copy headers from the authentication server to the request.
#
# Optional
#
[entryPoints.http.auth.forward.tls]
cert = "authserver.crt"
key = "authserver.key"
authResponseHeaders = ["X-Auth-User", "X-Secret"]
# Enable forward auth TLS connection.
#
# Optional
#
[entryPoints.http.auth.forward.tls]
ca = "path/to/local.crt"
caOptional = true
cert = "path/to/foo.cert"
key = "path/to/foo.key"
```
## Specify Minimum TLS Version
@@ -339,6 +415,40 @@ To specify an https entry point with a minimum TLS version, and specifying an ar
keyFile = "integration/fixtures/https/snitest.org.key"
```
## Strict SNI Checking
To enable strict SNI checking, so that connections cannot be made if a matching certificate does not exist.
```toml
[entryPoints]
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
sniStrict = true
[[entryPoints.https.tls.certificates]]
certFile = "integration/fixtures/https/snitest.com.cert"
keyFile = "integration/fixtures/https/snitest.com.key"
```
## Default Certificate
To enable a default certificate to serve, so that connections without SNI or without a matching domain will be served this certificate.
```toml
[entryPoints]
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[entryPoints.https.tls.defaultCertificate]
certFile = "integration/fixtures/https/snitest.com.cert"
keyFile = "integration/fixtures/https/snitest.com.key"
```
!!! note
There can only be one `defaultCertificate` set per entrypoint.
Use a single set of square brackets `[ ]`, instead of the two needed for normal certificates.
If no default certificate is provided, a self-signed certificate will be generated by Traefik, and used instead.
## Compression
To enable compression support using gzip format.

View File

@@ -18,6 +18,7 @@ logLevel = "INFO"
[accessLog.filters]
statusCodes = ["200", "300-302"]
retryAttempts = true
minDuration = "10ms"
[accessLog.fields]
defaultMode = "keep"
@@ -46,6 +47,7 @@ For more information about the CLI, see the documentation about [Traefik command
--accessLog.format="json"
--accessLog.filters.statusCodes="200,300-302"
--accessLog.filters.retryAttempts="true"
--accessLog.filters.minDuration="10ms"
--accessLog.fields.defaultMode="keep"
--accessLog.fields.names="Username=drop Hostname=drop"
--accessLog.fields.headers.defaultMode="keep"
@@ -124,6 +126,20 @@ filePath = "/path/to/access.log"
format = "json"
```
To write the logs in async, specify `bufferingSize` as the format (must be >0):
```toml
[accessLog]
filePath = "/path/to/access.log"
# Buffering Size
#
# Optional
# Default: 0
#
# Number of access log lines to process in a buffered way.
#
bufferingSize = 100
```
To filter logs you can specify a set of filters which are logically "OR-connected". Thus, specifying multiple filters will keep more access logs than specifying only one:
```toml
[accessLog]
@@ -132,19 +148,26 @@ format = "json"
[accessLog.filters]
# statusCodes keep access logs with status codes in the specified range
# statusCodes: keep access logs with status codes in the specified range
#
# Optional
# Default: []
#
statusCodes = ["200", "300-302"]
# retryAttempts keep access logs when at least one retry happened
# retryAttempts: keep access logs when at least one retry happened
#
# Optional
# Default: false
#
retryAttempts = true
# minDuration: keep access logs when request took longer than the specified duration
#
# Optional
# Default: 0
#
minDuration = "10ms"
```
To customize logs format:

View File

@@ -80,7 +80,8 @@
# ...
```
### InfluxDB
## InfluxDB
```toml
[metrics]
@@ -96,6 +97,13 @@
#
address = "localhost:8089"
# InfluxDB's address protocol (udp or http)
#
# Required
# Default: "udp"
#
protocol = "udp"
# InfluxDB push interval
#
# Optional
@@ -103,24 +111,19 @@
#
pushinterval = "10s"
# ...
```
## Statistics
```toml
# Metrics definition
[metrics]
# ...
# Enable more detailed statistics.
[metrics.statistics]
# Number of recent errors logged.
# InfluxDB database used when protocol is http
#
# Default: 10
# Optional
# Default: ""
#
recentErrors = 10
database = ""
# InfluxDB retention policy used when protocol is http
#
# Optional
# Default: ""
#
retentionpolicy = ""
# ...
```

View File

@@ -15,28 +15,28 @@ Træfik supports two backends: Jaeger and Zipkin.
#
# Default: "jaeger"
#
Backend = "jaeger"
backend = "jaeger"
# Service name used in Jaeger backend
#
# Default: "traefik"
#
ServiceName = "traefik"
serviceName = "traefik"
[tracing.jaeger]
# SamplingServerURL is the address of jaeger-agent's HTTP sampling server
# Sampling Server URL is the address of jaeger-agent's HTTP sampling server
#
# Default: "http://localhost:5778/sampling"
#
SamplingServerURL = "http://localhost:5778/sampling"
samplingServerURL = "http://localhost:5778/sampling"
# Sampling Type specifies the type of the sampler: const, probabilistic, rateLimiting
#
# Default: "const"
#
SamplingType = "const"
samplingType = "const"
# SamplingParam Param is a value passed to the sampler.
# Sampling Param is a value passed to the sampler.
# Valid values for Param field are:
# - for "const" sampler, 0 or 1 for always false/true respectively
# - for "probabilistic" sampler, a probability between 0 and 1
@@ -44,15 +44,18 @@ Træfik supports two backends: Jaeger and Zipkin.
#
# Default: 1.0
#
SamplingParam = 1.0
samplingParam = 1.0
# LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address
# Local Agent Host Port instructs reporter to send spans to jaeger-agent at this address
#
# Default: "127.0.0.1:6832"
# Default: "127.0.0.1:6831"
#
LocalAgentHostPort = "127.0.0.1:6832"
localAgentHostPort = "127.0.0.1:6831"
```
!!! warning
Træfik is only able to send data over compact thrift protocol to the [Jaeger agent](https://www.jaegertracing.io/docs/deployment/#agent).
## Zipkin
```toml
@@ -62,36 +65,74 @@ Træfik supports two backends: Jaeger and Zipkin.
#
# Default: "jaeger"
#
Backend = "zipkin"
backend = "zipkin"
# Service name used in Zipkin backend
#
# Default: "traefik"
#
ServiceName = "traefik"
serviceName = "traefik"
[tracing.zipkin]
# Zipking HTTP endpoint used to send data
#
# Default: "http://localhost:9411/api/v1/spans"
#
HTTPEndpoint = "http://localhost:9411/api/v1/spans"
httpEndpoint = "http://localhost:9411/api/v1/spans"
# Enable Zipkin debug
#
# Default: false
#
Debug = false
debug = false
# Use ZipKin SameSpan RPC style traces
#
# Default: false
#
SameSpan = false
sameSpan = false
# Use ZipKin 128 bit root span IDs
#
# Default: true
#
ID128Bit = true
id128Bit = true
```
## DataDog
```toml
# Tracing definition
[tracing]
# Backend name used to send tracing data
#
# Default: "jaeger"
#
backend = "datadog"
# Service name used in DataDog backend
#
# Default: "traefik"
#
serviceName = "traefik"
[tracing.datadog]
# Local Agent Host Port instructs reporter to send spans to datadog-tracing-agent at this address
#
# Default: "127.0.0.1:8126"
#
localAgentHostPort = "127.0.0.1:8126"
# Enable DataDog debug
#
# Default: false
#
debug = false
# Apply shared tag in a form of Key:Value to all the traces
#
# Default: ""
#
globalTag = ""
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 274 KiB

View File

@@ -3,29 +3,30 @@
</p>
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](https://docs.traefik.io)
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](/)
[![Go Report Card](https://goreportcard.com/badge/github.com/containous/traefik)](https://goreportcard.com/report/github.com/containous/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/containous/traefik/blob/master/LICENSE.md)
[![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
[![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
[![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy)
Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
Telling Træfik where your orchestrator is could be the _only_ configuration step you need to do.
Pointing Træfik at your orchestrator should be the _only_ configuration step you need.
## Overview
Imagine that you have deployed a bunch of microservices with the help of an orchestrator (like Swarm or Kubernetes) or a service registry (like etcd or consul).
Now you want users to access these microservices, and you need a reverse proxy.
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice. In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
**This is when Træfik can help you!**
Træfik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
Træfik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
**Run Træfik and let it do the work for you!**
**Run Træfik and let it do the work for you!**
_(But if you'd rather configure some of your routes manually, Træfik supports that too!)_
![Architecture](img/architecture.png)
@@ -41,18 +42,18 @@ _(But if you'd rather configure some of your routes manually, Træfik supports t
- Websocket, HTTP/2, GRPC ready
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB)
- Keeps access logs (JSON, CLF)
- [Fast](/benchmarks) ... which is nice
- Fast
- Exposes a Rest API
- Packaged as a single binary file (made with :heart: with go) and available as a [tiny](https://microbadger.com/images/traefik) [official](https://hub.docker.com/r/_/traefik/) docker image
## Supported backends
## Supported Providers
- [Docker](/configuration/backends/docker/) / [Swarm mode](/configuration/backends/docker/#docker-swarm-mode)
- [Kubernetes](/configuration/backends/kubernetes/)
- [Mesos](/configuration/backends/mesos/) / [Marathon](/configuration/backends/marathon/)
- [Rancher](/configuration/backends/rancher/) (API, Metadata)
- [Service Fabric](/configuration/backends/servicefabric/)
- [Azure Service Fabric](/configuration/backends/servicefabric/)
- [Consul Catalog](/configuration/backends/consulcatalog/)
- [Consul](/configuration/backends/consul/) / [Etcd](/configuration/backends/etcd/) / [Zookeeper](/configuration/backends/zookeeper/) / [BoltDB](/configuration/backends/boltdb/)
- [Eureka](/configuration/backends/eureka/)
@@ -76,13 +77,13 @@ version: '3'
services:
reverse-proxy:
image: traefik #The official Traefik docker image
command: --api --docker #Enables the web UI and tells Træfik to listen to docker
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
ports:
- "80:80" #The HTTP port
- "8080:8080" #The Web UI (enabled by --api)
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock #So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
```
**That's it. Now you can launch Træfik!**
@@ -90,21 +91,21 @@ services:
Start your `reverse-proxy` with the following command:
```shell
docker-compose up -d reverse-proxy
docker-compose up -d reverse-proxy
```
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Træfik's dashboard (we'll go back there once we have launched a service in step 2).
### 2 — Launch a Service — Træfik Detects It and Creates a Route for You
### 2 — Launch a Service — Træfik Detects It and Creates a Route for You
Now that we have a Træfik instance up and running, we will deploy new services.
Now that we have a Træfik instance up and running, we will deploy new services.
Edit your `docker-compose.yml` file and add the following at the end of your file.
Edit your `docker-compose.yml` file and add the following at the end of your file.
```yaml
# ...
# ...
whoami:
image: emilevauge/whoami #A container that exposes an API to show it's IP address
image: emilevauge/whoami # A container that exposes an API to show its IP address
labels:
- "traefik.frontend.rule=Host:whoami.docker.localhost"
```
@@ -112,7 +113,7 @@ Edit your `docker-compose.yml` file and add the following at the end of your fil
The above defines `whoami`: a simple web service that outputs information about the machine it is deployed on (its IP address, host, and so on).
Start the `whoami` service with the following command:
```shell
docker-compose up -d whoami
```
@@ -135,9 +136,9 @@ IP: 172.27.0.3
### 3 — Launch More Instances — Traefik Load Balances Them
Run more instances of your `whoami` service with the following command:
```shell
docker-compose up -d --scale whoami=2
docker-compose up -d --scale whoami=2
```
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Træfik has automatically detected the new instance of the container.
@@ -164,9 +165,10 @@ IP: 172.27.0.4
### 4 — Enjoy Træfik's Magic
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](https://docs.traefik.io/) and let Træfik work for you! Whatever your infrastructure is, there is probably [an available Træfik backend](https://docs.traefik.io/configuration/backends/available) that will do the job.
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](/) and let Træfik work for you!
Whatever your infrastructure is, there is probably [an available Træfik provider](/#supported-providers) that will do the job.
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](https://docs.traefik.io/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/).
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](/user-guide/docker-and-lets-encrypt/).
## Resources
@@ -196,4 +198,4 @@ Using the tiny Docker image:
```shell
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik
```
```

View File

@@ -9,9 +9,9 @@ If you want to use Let's Encrypt with Træfik, sharing configuration or TLS cert
Ok, could we mount a shared volume used by all my instances? Yes, you can, but it will not work.
When you use Let's Encrypt, you need to store certificates, but not only.
When Træfik generates a new certificate, it configures a challenge and once Let's Encrypt will verify the ownership of the domain, it will ping back the challenge.
If the challenge is not knowing by other Træfik instances, the validation will fail.
If the challenge is not known by other Træfik instances, the validation will fail.
For more information about challenge: [Automatic Certificate Management Environment (ACME)](https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http-challenge)
For more information about the challenge: [Automatic Certificate Management Environment (ACME)](https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#http-challenge)
## Prerequisites
@@ -77,12 +77,12 @@ TL;DR:
```shell
$ traefik \
--docker \
--docker.swarmmode \
--docker.swarmMode \
--docker.domain=mydomain.ca \
--docker.watch
```
To enable docker and swarm-mode support, you need to add `--docker` and `--docker.swarmmode` flags.
To enable docker and swarm-mode support, you need to add `--docker` and `--docker.swarmMode` flags.
To watch docker events, add `--docker.watch`.
### Full docker-compose file
@@ -101,11 +101,11 @@ services:
- "--acme.storage=/etc/traefik/acme/acme.json"
- "--acme.entryPoint=https"
- "--acme.httpChallenge.entryPoint=http"
- "--acme.OnHostRule=true"
- "--acme.onHostRule=true"
- "--acme.onDemand=false"
- "--acme.email=contact@mydomain.ca"
- "--docker"
- "--docker.swarmmode"
- "--docker.swarmMode"
- "--docker.domain=mydomain.ca"
- "--docker.watch"
volumes:
@@ -211,11 +211,11 @@ services:
- "--acme.storage=traefik/acme/account"
- "--acme.entryPoint=https"
- "--acme.httpChallenge.entryPoint=http"
- "--acme.OnHostRule=true"
- "--acme.onHostRule=true"
- "--acme.onDemand=false"
- "--acme.email=foobar@example.com"
- "--docker"
- "--docker.swarmmode"
- "--docker.swarmMode"
- "--docker.domain=example.com"
- "--docker.watch"
- "--consul"

View File

@@ -26,8 +26,8 @@ If this instance fails, another manager will be automatically elected.
## Træfik cluster and Let's Encrypt
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#storage-kv-entry).**
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#as-a-key-value-store-entry).**
Thanks to the Træfik cluster mode algorithm (based on [the Raft Consensus Algorithm](https://raft.github.io/)), only one instance will contact Let's encrypt to solve the challenges.
The others instances will get ACME certificate from the KV Store entry.
The others instances will get ACME certificate from the KV Store entry.

View File

@@ -50,7 +50,7 @@ version: '2'
services:
traefik:
image: traefik:1.3.5
image: traefik:1.5.4
restart: always
ports:
- 80:80
@@ -97,13 +97,13 @@ defaultEntryPoints = ["https","http"]
endpoint = "unix:///var/run/docker.sock"
domain = "my-awesome-app.org"
watch = true
exposedbydefault = false
exposedByDefault = false
[acme]
email = "your-email-here@my-awesome-app.org"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
```
@@ -113,7 +113,7 @@ This is the minimum configuration required to do the following:
- Log `ERROR`-level messages (or more severe) to the console, but silence `DEBUG`-level messages
- Check for new versions of Træfik periodically
- Create two entry points, namely an `HTTP` endpoint on port `80`, and an `HTTPS` endpoint on port `443` where all incoming traffic on port `80` will immediately get redirected to `HTTPS`.
- Enable the Docker configuration backend and listen for container events on the Docker unix socket we've mounted earlier. However, **new containers will not be exposed by Træfik by default, we'll get into this in a bit!**
- Enable the Docker provider and listen for container events on the Docker unix socket we've mounted earlier. However, **new containers will not be exposed by Træfik by default, we'll get into this in a bit!**
- Enable automatic request and configuration of SSL certificates using Let's Encrypt.
These certificates will be stored in the `acme.json` file, which you can back-up yourself and store off-premises.
@@ -123,7 +123,7 @@ Alright, let's boot the container. From the `/opt/traefik` directory, run `docke
Now that we've fully configured and started Træfik, it's time to get our applications running!
Let's take a simple example of a micro-service project consisting of various services, where some will be exposed to the outside world and some will not.
Let's take a simple example of a micro-service project consisting of various services, where some will be exposed to the outside world and some will not.
The `docker-compose.yml` of our project looks like this:
@@ -145,12 +145,11 @@ services:
expose:
- "9000"
labels:
- "traefik.backend=my-awesome-app-app"
- "traefik.docker.network=web"
- "traefik.frontend.rule=Host:app.my-awesome-app.org"
- "traefik.enable=true"
- "traefik.port=9000"
- "traefik.default.protocol=http"
- "traefik.basic.frontend.rule=Host:app.my-awesome-app.org"
- "traefik.basic.port=9000"
- "traefik.basic.protocol=http"
- "traefik.admin.frontend.rule=Host:admin-app.my-awesome-app.org"
- "traefik.admin.protocol=https"
- "traefik.admin.port=9443"
@@ -204,12 +203,11 @@ Thanks to Docker labels, we can tell Træfik how to create its internal routing
Let's take a look at the labels themselves for the `app` service, which is a HTTP webservice listing on port 9000:
```yaml
- "traefik.backend=my-awesome-app-app"
- "traefik.docker.network=web"
- "traefik.frontend.rule=Host:app.my-awesome-app.org"
- "traefik.enable=true"
- "traefik.port=9000"
- "traefik.default.protocol=http"
- "traefik.basic.frontend.rule=Host:app.my-awesome-app.org"
- "traefik.basic.port=9000"
- "traefik.basic.protocol=http"
- "traefik.admin.frontend.rule=Host:admin-app.my-awesome-app.org"
- "traefik.admin.protocol=https"
- "traefik.admin.port=9443"
@@ -221,11 +219,11 @@ We use both `container labels` and `service labels`.
First, we specify the `backend` name which corresponds to the actual service we're routing **to**.
We also tell Træfik to use the `web` network to route HTTP traffic to this container.
We also tell Træfik to use the `web` network to route HTTP traffic to this container.
With the `traefik.enable` label, we tell Træfik to include this container in its internal configuration.
With the `frontend.rule` label, we tell Træfik that we want to route to this container if the incoming HTTP request contains the `Host` `app.my-awesome-app.org`.
Essentially, this is the actual rule used for Layer-7 load balancing.
Essentially, this is the actual rule used for Layer-7 load balancing.
Finally but not unimportantly, we tell Træfik to route **to** port `9000`, since that is the actual TCP/IP port the container actually listens on.
@@ -236,11 +234,11 @@ Finally but not unimportantly, we tell Træfik to route **to** port `9000`, sinc
When both `container labels` and `service labels` are defined, `container labels` are just used as default values for missing `service labels` but no frontend/backend are going to be defined only with these labels.
Obviously, labels `traefik.frontend.rule` and `traefik.port` described above, will only be used to complete information set in `service labels` during the container frontends/bakends creation.
In the example, two service names are defined : `default` and `admin`.
In the example, two service names are defined : `basic` and `admin`.
They allow creating two frontends and two backends.
- `default` has only one `service label` : `traefik.default.protocol`.
Træfik will use values set in `traefik.frontend.rule` and `traefik.port` to create the `default` frontend and backend.
- `basic` has only one `service label` : `traefik.basic.protocol`.
Træfik will use values set in `traefik.frontend.rule` and `traefik.port` to create the `basic` frontend and backend.
The frontend listens to incoming HTTP requests which contain the `Host` `app.my-awesome-app.org` and redirect them in `HTTP` to the port `9000` of the backend.
- `admin` has all the `services labels` needed to create the `admin` frontend and backend (`traefik.admin.frontend.rule`, `traefik.admin.protocol`, `traefik.admin.port`).
Træfik will create a frontend to listen to incoming HTTP requests which contain the `Host` `admin-app.my-awesome-app.org` and redirect them in `HTTPS` to the port `9443` of the backend.
@@ -250,7 +248,7 @@ Træfik will create a frontend to listen to incoming HTTP requests which contain
- Always specify the correct port where the container expects HTTP traffic using `traefik.port` label.
If a container exposes multiple ports, Træfik may forward traffic to the wrong port.
Even if a container only exposes one port, you should always write configuration defensively and explicitly.
- Should you choose to enable the `exposedbydefault` flag in the `traefik.toml` configuration, be aware that all containers that are placed in the same network as Træfik will automatically be reachable from the outside world, for everyone and everyone to see.
- Should you choose to enable the `exposedByDefault` flag in the `traefik.toml` configuration, be aware that all containers that are placed in the same network as Træfik will automatically be reachable from the outside world, for everyone and everyone to see.
Usually, this is a bad idea.
- With the `traefik.frontend.auth.basic` label, it's possible for Træfik to provide a HTTP basic-auth challenge for the endpoints you provide the label for.
- Træfik has built-in support to automatically export [Prometheus](https://prometheus.io) metrics

View File

@@ -68,7 +68,7 @@ defaultEntryPoints = ["http", "https"]
[acme]
email = "test@traefik.io"
storage = "acme.json"
caServer = "http://172.18.0.1:4000/directory"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"
@@ -89,7 +89,7 @@ This configuration allows generating Let's Encrypt certificates (thanks to `HTTP
Træfik generates these certificates when it starts and it needs to be restart if new domains are added.
### OnHostRule option (with HTTP challenge)
### onHostRule option (with HTTP challenge)
```toml
[entryPoints]
@@ -103,7 +103,7 @@ Træfik generates these certificates when it starts and it needs to be restart i
email = "test@traefik.io"
storage = "acme.json"
onHostRule = true
caServer = "http://172.18.0.1:4000/directory"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"
@@ -140,7 +140,7 @@ If a backend is added with a `onHost` rule, Træfik will automatically generate
email = "test@traefik.io"
storage = "acme.json"
onDemand = true
caServer = "http://172.18.0.1:4000/directory"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"
@@ -167,7 +167,7 @@ This configuration allows generating a Let's Encrypt certificate (thanks to `HTT
[acme]
email = "test@traefik.io"
storage = "acme.json"
caServer = "http://172.18.0.1:4000/directory"
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
entryPoint = "https"
[acme.dnsChallenge]
provider = "digitalocean" # DNS Provider name (cloudflare, OVH, gandi...)
@@ -223,9 +223,9 @@ These variables have to be set on the machine/container that host Træfik.
These variables are described [in this section](/configuration/acme/#provider).
More information about wildcard certificates are available [in this section](/configuration/acme/#wildcard-domain).
More information about wildcard certificates are available [in this section](/configuration/acme/#wildcard-domains).
### OnHostRule option and provided certificates (with HTTP challenge)
### onHostRule option and provided certificates (with HTTP challenge)
```toml
[entryPoints]
@@ -322,43 +322,7 @@ The `consul` provider contains the configuration.
rule = "Path:/test"
```
## Enable Basic authentication in an entry point
With two user/pass:
- `test`:`test`
- `test2`:`test2`
Passwords are encoded in MD5: you can use `htpasswd` to generate them.
```toml
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth.basic]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
```
## Pass Authenticated user to application via headers
Providing an authentication method as described above, it is possible to pass the user to the application
via a configurable header value.
```toml
defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.auth]
headerField = "X-WebAuth-User"
[entryPoints.http.auth.basic]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
```
## Override the Traefik HTTP server IdleTimeout and/or throttle configurations from re-loading too quickly
## Override the Traefik HTTP server idleTimeout and/or throttle configurations from re-loading too quickly
```toml
providersThrottleDuration = "5s"

View File

@@ -1,15 +1,53 @@
# gRPC example
# gRPC examples
## With HTTP (h2c)
This section explains how to use Traefik as reverse proxy for gRPC application.
### Træfik configuration
At last, we configure our Træfik instance to use both self-signed certificates.
```toml
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http]
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
# Access on backend with h2c
url = "h2c://backend.local:8080"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:frontend.local"
```
!!! warning
For provider with label, you will have to specify the `traefik.protocol=h2c`
### Conclusion
We don't need specific configuration to use gRPC in Træfik, we just need to use `h2c` protocol, or use HTTPS communications to have HTTP2 with the backend.
## With HTTPS
This section explains how to use Traefik as reverse proxy for gRPC application with self-signed certificates.
!!! warning
As gRPC needs HTTP2, we need HTTPS certificates on both gRPC Server and Træfik.
![gRPC architecture](/img/grpc.svg)
<p align="center">
<img src="/img/grpc.svg" alt="gRPC architecture" title="gRPC architecture" />
</p>
## gRPC Server certificate
### gRPC Server certificate
In order to secure the gRPC server, we generate a self-signed certificate for backend url:
@@ -23,7 +61,7 @@ That will prompt for information, the important answer is:
Common Name (e.g. server FQDN or YOUR name) []: backend.local
```
## gRPC Client certificate
### gRPC Client certificate
Generate your self-signed certificate for frontend url:
@@ -37,7 +75,7 @@ with
Common Name (e.g. server FQDN or YOUR name) []: frontend.local
```
## Træfik configuration
### Træfik configuration
At last, we configure our Træfik instance to use both self-signed certificates.
@@ -45,7 +83,7 @@ At last, we configure our Træfik instance to use both self-signed certificates.
defaultEntryPoints = ["https"]
# For secure connection on backend.local
RootCAs = [ "./backend.cert" ]
rootCAs = [ "./backend.cert" ]
[entryPoints]
[entryPoints.https]
@@ -76,15 +114,11 @@ RootCAs = [ "./backend.cert" ]
```
!!! warning
With some backends, the server URLs use the IP, so you may need to configure `InsecureSkipVerify` instead of the `RootCAS` to activate HTTPS without hostname verification.
With some backends, the server URLs use the IP, so you may need to configure `insecureSkipVerify` instead of the `rootCAS` to activate HTTPS without hostname verification.
## Conclusion
### A gRPC example in go (modify for https)
We don't need specific configuration to use gRPC in Træfik, we just need to be careful that all the exchanges (between client and Træfik, and between Træfik and backend) are HTTPS communications because gRPC uses HTTP2.
## A gRPC example in go
We will use the gRPC greeter example in [grpc-go](https://github.com/grpc/grpc-go/tree/master/examples/helloworld)
We use the gRPC greeter example in [grpc-go](https://github.com/grpc/grpc-go/tree/master/examples/helloworld)
!!! warning
In order to use this gRPC example, we need to modify it to use HTTPS
@@ -147,4 +181,3 @@ r, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: name})
// ...
```

View File

@@ -81,9 +81,11 @@ For namespaced restrictions, one RoleBinding is required per watched namespace a
It is possible to use Træfik with a [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) object,
whereas both options have their own pros and cons:
- The scalability is much better when using a Deployment, because you will have a Single-Pod-per-Node model when using the DaemonSet.
- It is possible to exclusively run a Service on a dedicated set of machines using taints and tolerations with a DaemonSet.
- On the other hand the DaemonSet allows you to access any Node directly on Port 80 and 443, where you have to setup a [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with a Deployment.
- The scalability can be much better when using a Deployment, because you will have a Single-Pod-per-Node model when using a DaemonSet, whereas you may need less replicas based on your environment when using a Deployment.
- DaemonSets automatically scale to new nodes, when the nodes join the cluster, whereas Deployment pods are only scheduled on new nodes if required.
- DaemonSets ensure that only one replica of pods run on any single node. Deployments require affinity settings if you want to ensure that two pods don't end up on the same node.
- DaemonSets can be run with the `NET_BIND_SERVICE` capability, which will allow it to bind to port 80/443/etc on each host. This will allow bypassing the kube-proxy, and reduce traffic hops. Note that this is against the Kubernetes Best Practices [Guidelines](https://kubernetes.io/docs/concepts/configuration/overview/#services), and raises the potential for scheduling/scaling issues. Despite potential issues, this remains the choice for most ingress controllers.
- If you are unsure which to choose, start with the Daemonset.
The Deployment objects looks like this:
@@ -118,6 +120,11 @@ spec:
containers:
- image: traefik
name: traefik-ingress-lb
ports:
- name: http
containerPort: 80
- name: admin
containerPort: 8080
args:
- --api
- --kubernetes
@@ -172,7 +179,6 @@ spec:
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
hostNetwork: true
containers:
- image: traefik
name: traefik-ingress-lb
@@ -208,11 +214,13 @@ spec:
- protocol: TCP
port: 8080
name: admin
type: NodePort
```
[examples/k8s/traefik-ds.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/traefik-ds.yaml)
!!! note
This will create a Daemonset that uses privileged ports 80/8080 on the host. This may not work on all providers, but illustrates the static (non-NodePort) hostPort binding. The `traefik-ingress-service` can still be used inside the cluster to access the DaemonSet pods.
To deploy Træfik to your cluster start by submitting one of the YAML files to the cluster with `kubectl`:
```shell
@@ -293,7 +301,21 @@ Install the Træfik chart by:
```shell
helm install stable/traefik
```
Install the Træfik chart using a values.yaml file.
```shell
helm install --values values.yaml stable/traefik
```
```yaml
dashboard:
enabled: true
domain: traefik-ui.minikube
kubernetes:
namespaces:
- default
- kube-system
```
For more information, check out [the documentation](https://github.com/kubernetes/charts/tree/master/stable/traefik).
## Submitting an Ingress to the Cluster
@@ -310,7 +332,8 @@ spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- port: 80
- name: web
port: 80
targetPort: 8080
---
apiVersion: extensions/v1beta1
@@ -318,16 +341,15 @@ kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: traefik-ui.minikube
http:
paths:
- backend:
- path: /
backend:
serviceName: traefik-web-ui
servicePort: 80
servicePort: web
```
[examples/k8s/ui.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/ui.yaml)
@@ -350,7 +372,8 @@ We should now be able to visit [traefik-ui.minikube](http://traefik-ui.minikube)
### Add a TLS Certificate to the Ingress
!!! note
For this example to work you need a TLS entrypoint. You don't have to provide a TLS certificate at this point. For more details see [here](/configuration/entrypoints/).
For this example to work you need a TLS entrypoint. You don't have to provide a TLS certificate at this point.
For more details see [here](/configuration/entrypoints/).
To setup an HTTPS-protected ingress, you can leverage the TLS feature of the ingress resource.
@@ -371,10 +394,11 @@ spec:
serviceName: traefik-web-ui
servicePort: 80
tls:
secretName: traefik-ui-tls-cert
- secretName: traefik-ui-tls-cert
```
In addition to the modified ingress you need to provide the TLS certificate via a Kubernetes secret in the same namespace as the ingress. The following two commands will generate a new certificate and create a secret containing the key and cert files.
In addition to the modified ingress you need to provide the TLS certificate via a Kubernetes secret in the same namespace as the ingress.
The following two commands will generate a new certificate and create a secret containing the key and cert files.
```shell
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=traefik-ui.minikube"
@@ -384,13 +408,16 @@ kubectl -n kube-system create secret tls traefik-ui-tls-cert --key=tls.key --cer
If there are any errors while loading the TLS section of an ingress, the whole ingress will be skipped.
!!! note
The secret must have two entries named `tls.key`and `tls.crt`. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) for more details.
The secret must have two entries named `tls.key`and `tls.crt`.
See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) for more details.
!!! note
The TLS certificates will be added to all entrypoints defined by the ingress annotation `traefik.frontend.entryPoints`. If no such annotation is provided, the TLS certificates will be added to all TLS-enabled `defaultEntryPoints`.
The TLS certificates will be added to all entrypoints defined by the ingress annotation `traefik.frontend.entryPoints`.
If no such annotation is provided, the TLS certificates will be added to all TLS-enabled `defaultEntryPoints`.
!!! note
The field `hosts` in the TLS configuration is ignored. Instead, the domains provided by the certificate are used for this purpose. It is recommended to not use wildcard certificates as they will match globally.
The field `hosts` in the TLS configuration is ignored. Instead, the domains provided by the certificate are used for this purpose.
It is recommended to not use wildcard certificates as they will match globally.
## Basic Authentication
@@ -398,7 +425,7 @@ It's possible to protect access to Træfik through basic authentication. (See th
### Creating the Secret
A. Use `htpasswd` to create a file containing the username and the base64-encoded password:
A. Use `htpasswd` to create a file containing the username and the MD5-encoded password:
```shell
htpasswd -c ./auth myusername
@@ -831,13 +858,106 @@ Sometimes Træfik runs along other Ingress controller implementations. One such
The `kubernetes.io/ingress.class` annotation can be attached to any Ingress object in order to control whether Træfik should handle it.
If the annotation is missing, contains an empty value, or the value `traefik`, then the Træfik controller will take responsibility and process the associated Ingress object. If the annotation contains any other value (usually the name of a different Ingress controller), Træfik will ignore the object.
If the annotation is missing, contains an empty value, or the value `traefik`, then the Træfik controller will take responsibility and process the associated Ingress object.
It is also possible to set the `ingressClass` option in Træfik to a particular value. Træfik will only process matching Ingress objects.
For instance, setting the option to `traefik-internal` causes Træfik to process Ingress objects with the same `kubernetes.io/ingress.class` annotation value, ignoring all other objects (including those with a `traefik` value, empty value, and missing annotation).
!!! note
Letting multiple ingress controllers handle the same ingress objects can lead to unintended behavior.
It is recommended to prefix all ingressClass values with `traefik` to avoid unintended collisions with other ingress implementations.
### Between multiple Træfik Deployments
Sometimes multiple Træfik Deployments are supposed to run concurrently. For instance, it is conceivable to have one Deployment deal with internal and another one with external traffic.
Sometimes multiple Træfik Deployments are supposed to run concurrently.
For instance, it is conceivable to have one Deployment deal with internal and another one with external traffic.
For such cases, it is advisable to classify Ingress objects through a label and configure the `labelSelector` option per each Træfik Deployment accordingly. To stick with the internal/external example above, all Ingress objects meant for internal traffic could receive a `traffic-type: internal` label while objects designated for external traffic receive a `traffic-type: external` label. The label selectors on the Træfik Deployments would then be `traffic-type=internal` and `traffic-type=external`, respectively.
For such cases, it is advisable to classify Ingress objects through a label and configure the `labelSelector` option per each Træfik Deployment accordingly.
To stick with the internal/external example above, all Ingress objects meant for internal traffic could receive a `traffic-type: internal` label while objects designated for external traffic receive a `traffic-type: external` label.
The label selectors on the Træfik Deployments would then be `traffic-type=internal` and `traffic-type=external`, respectively.
## Traffic Splitting
It is possible to split Ingress traffic in a fine-grained manner between multiple deployments using _service weights_.
One canonical use case is canary releases where a deployment representing a newer release is to receive an initially small but ever-increasing fraction of the requests over time.
The way this can be done in Træfik is to specify a percentage of requests that should go into each deployment.
For instance, say that an application `my-app` runs in version 1.
A newer version 2 is about to be released, but confidence in the robustness and reliability of new version running in production can only be gained gradually.
Thus, a new deployment `my-app-canary` is created and scaled to a replica count that suffices for a 1% traffic share.
Along with it, a Service object is created as usual.
The Ingress specification would look like this:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/service-weights: |
my-app: 99%
my-app-canary: 1%
name: my-app
spec:
rules:
- http:
paths:
- backend:
serviceName: my-app
servicePort: 80
path: /
- backend:
serviceName: my-app-canary
servicePort: 80
path: /
```
Take note of the `traefik.ingress.kubernetes.io/service-weights` annotation: It specifies the distribution of requests among the referenced backend services, `my-app` and `my-app-canary`.
With this definition, Træfik will route 99% of the requests to the pods backed by the `my-app` deployment, and 1% to those backed by `my-app-canary`.
Over time, the ratio may slowly shift towards the canary deployment until it is deemed to replace the previous main application, in steps such as 5%/95%, 10%/90%, 50%/50%, and finally 100%/0%.
A few conditions must hold for service weights to be applied correctly:
- The associated service backends must share the same path and host.
- The total percentage shared across all service backends must yield 100% (see the section on [omitting the final service](#omitting-the-final-service), however).
- The percentage values are interpreted as floating point numbers to a supported precision as defined in the [annotation documentation](/configuration/backends/kubernetes#general-annotations).
### Omitting the Final Service
When specifying service weights, it is possible to omit exactly one service for convenience reasons.
For instance, the following definition shows how to split requests in a scenario where a canary release is accompanied by a baseline deployment for easier metrics comparison or automated canary analysis:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/service-weights: |
my-app-canary: 10%
my-app-baseline: 10%
name: app
spec:
rules:
- http:
paths:
- backend:
serviceName: my-app-canary
servicePort: 80
path: /
- backend:
serviceName: my-app-baseline
servicePort: 80
path: /
- backend:
serviceName: my-app-main
servicePort: 80
path: /
```
This configuration assigns 80% of traffic to `my-app-main` automatically, thus freeing the user from having to complete percentage values manually.
This becomes handy when increasing shares for canary releases continuously.
## Production advice

View File

@@ -56,7 +56,7 @@ whoami4:
### Upload the configuration in the Key-value store
We should now fill the store with the Træfik global configuration, as we do with a [TOML file configuration](/toml).
We should now fill the store with the Træfik global configuration.
To do that, we can send the Key-value pairs via [curl commands](https://www.consul.io/intro/getting-started/kv.html) or via the [Web UI](https://www.consul.io/intro/getting-started/ui.html).
Fortunately, Træfik allows automation of this process using the `storeconfig` subcommand.
@@ -76,7 +76,7 @@ defaultEntryPoints = ["http", "https"]
address = ":80"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "integration/fixtures/https/snitest.com.cert"
@@ -85,9 +85,9 @@ defaultEntryPoints = ["http", "https"]
certFile = """-----BEGIN CERTIFICATE-----
<cert file content>
-----END CERTIFICATE-----"""
keyFile = """-----BEGIN CERTIFICATE-----
keyFile = """-----BEGIN PRIVATE KEY-----
<key file content>
-----END CERTIFICATE-----"""
-----END PRIVATE KEY-----"""
[entryPoints.other-https]
address = ":4443"
[entryPoints.other-https.tls]
@@ -164,7 +164,7 @@ If a Consul ACL is used to restrict Træfik read/write access, one of the follow
key "traefik" {
policy = "write"
},
session "" {
policy = "write"
}
@@ -266,6 +266,11 @@ Here is the toml configuration we would like to store in the store :
backend = "backend1"
passHostHeader = true
priority = 10
[frontends.frontend2.auth.basic]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
entrypoints = ["https"] # overrides defaultEntryPoints
[frontends.frontend2.routes.test_1]
rule = "Host:{subdomain:[a-z]+}.localhost"
@@ -325,13 +330,15 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi
- frontend 2
| Key | Value |
|----------------------------------------------------|--------------------|
| `/traefik/frontends/frontend2/backend` | `backend1` |
| `/traefik/frontends/frontend2/passhostheader` | `true` |
| `/traefik/frontends/frontend2/priority` | `10` |
| `/traefik/frontends/frontend2/entrypoints` | `http,https` |
| `/traefik/frontends/frontend2/routes/test_2/rule` | `PathPrefix:/test` |
| Key | Value |
|----------------------------------------------------|-----------------------------------------------|
| `/traefik/frontends/frontend2/backend` | `backend1` |
| `/traefik/frontends/frontend2/passhostheader` | `true` |
| `/traefik/frontends/frontend2/priority` | `10` |
| `/traefik/frontends/frontend2/auth/basic/users/0` | `test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/` |
| `/traefik/frontends/frontend2/auth/basic/users/1` | `test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0` |
| `/traefik/frontends/frontend2/entrypoints` | `http,https` |
| `/traefik/frontends/frontend2/routes/test_2/rule` | `PathPrefix:/test` |
- certificate 1
@@ -349,7 +356,7 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi
|---------------------------------------|-----------------------|
| `/traefik/tls/2/entrypoints` | `https,other-https` |
| `/traefik/tls/2/certificate/certfile` | `<cert file content>` |
| `/traefik/tls/2/certificate/certfile` | `<key file content>` |
| `/traefik/tls/2/certificate/keyfile` | `<key file content>` |
### Atomic configuration changes
@@ -422,7 +429,7 @@ Træfik will not start but the [static configuration](/basics/#static-trfik-conf
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
If you configured a file backend `[file]`, all your dynamic configuration (backends, frontends...) will be uploaded to the Key-value store.
If you configured a file provider `[file]`, all your dynamic configuration (backends, frontends...) will be uploaded to the Key-value store.
To upload your ACME certificates to the KV store, get your Traefik TOML file and add the new `storage` option in the `acme` section:
@@ -438,4 +445,4 @@ Then remove the line `storageFile = "acme.json"` from your TOML config file.
That's it!
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -30,7 +30,7 @@ Following is the order by which Traefik tries to identify the port (the first on
## Applications with multiple ports
Some Marathon applications may expose multiple ports. Traefik supports creating one so-called _service_ per port using [specific labels](/configuration/backends/marathon#service-level).
Some Marathon applications may expose multiple ports. Traefik supports creating one so-called _segment_ per port using [segment labels](/configuration/backends/marathon#applications-with-multiple-ports-segment-labels).
For instance, assume that a Marathon application exposes a web API on port 80 and an admin interface on port 8080. It would then be possible to make each service available by specifying the following Marathon labels:

View File

@@ -87,7 +87,7 @@ docker-machine ssh manager "docker service create \
--network traefik-net \
traefik \
--docker \
--docker.swarmmode \
--docker.swarmMode \
--docker.domain=traefik \
--docker.watch \
--api"
@@ -101,8 +101,8 @@ Let's explain this command:
| `--constraint=node.role==manager` | we ask docker to schedule Træfik on a manager node. |
| `--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock` | we bind mount the docker socket where Træfik is scheduled to be able to speak to the daemon. |
| `--network traefik-net` | we attach the Træfik service (and thus the underlying container) to the `traefik-net` network. |
| `--docker` | enable docker backend, and `--docker.swarmmode` to enable the swarm mode on Træfik. |
| `--api | activate the webUI on port 8080 |
| `--docker` | enable docker provider, and `--docker.swarmMode` to enable the swarm mode on Træfik. |
| `--api` | activate the webUI on port 8080 |
## Deploy your apps
@@ -330,4 +330,4 @@ X-Forwarded-Proto: http
X-Forwarded-Server: 77fc29c69fe4
```
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -104,7 +104,7 @@ Let's explain this command:
| `--net=my-net` | run the container on the network my-net |
| `-v /var/lib/boot2docker/:/ssl` | mount the ssl keys generated by docker-machine |
| `-c /dev/null` | empty config file |
| `--docker` | enable docker backend |
| `--docker` | enable docker provider |
| `--docker.endpoint=tcp://172.18.0.1:2376` | connect to the swarm master using the docker_gwbridge network |
| `--docker.tls` | enable TLS using the docker-machine keys |
| `--api` | activate the webUI on port 8080 |
@@ -178,4 +178,4 @@ X-Forwarded-Proto: http
X-Forwarded-Server: 8fbc39271b4c
```
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)

View File

@@ -29,10 +29,13 @@ entryPoint = "api"
method = "drr"
[backends.backend.servers.server1]
url = "http://127.0.0.1:8081"
weight = 1
[backends.backend.servers.server2]
url = "http://127.0.0.1:8082"
weight = 1
[backends.backend.servers.server3]
url = "http://127.0.0.1:8083"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"

View File

@@ -27,18 +27,24 @@ entryPoint = "api"
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:8081"
weight = 1
[backends.backend2]
[backends.backend2.LoadBalancer]
method = "drr"
[backends.backend2.servers.server1]
url = "http://127.0.0.1:8082"
weight = 1
[backends.backend2.servers.server2]
url = "http://127.0.0.1:8083"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path: /test1"
[frontends.frontend2]
backend = "backend2"
passHostHeader = true

View File

@@ -16,7 +16,7 @@ email = "test@traefik.io"
storage = "/etc/traefik/conf/acme.json"
entryPoint = "https"
onDemand = false
OnHostRule = true
onHostRule = true
caServer = "http://traefik.boulder.com:4001/directory"
[acme.httpChallenge]
entryPoint="http"
@@ -27,6 +27,6 @@ caServer = "http://traefik.boulder.com:4001/directory"
endpoint = "unix:///var/run/docker.sock"
domain = "traefik.localhost.com"
watch = true
exposedbydefault = false
exposedByDefault = false

View File

@@ -9,7 +9,7 @@ readonly doc_file=$basedir"/docker-compose.yml"
down_environment() {
echo "STOP Docker environment"
! docker-compose -f $doc_file down -v &>/dev/null && \
echo "[ERROR] Impossible to stop the Docker environment" && exit 11
echo "[ERROR] Unable to stop the Docker environment" && exit 11
}
# Create and start Docker-compose environment or subpart of its services (if services are listed)
@@ -17,7 +17,7 @@ down_environment() {
up_environment() {
echo "START Docker environment"
! docker-compose -f $doc_file up -d $@ &>/dev/null && \
echo "[ERROR] Impossible to start Docker environment" && exit 21
echo "[ERROR] Unable to start Docker environment" && exit 21
}
# Init the environment : get IP address and create needed files
@@ -40,7 +40,7 @@ start_boulder() {
sleep 5
let waiting_counter-=1
if [[ $waiting_counter -eq 0 ]]; then
echo "[ERROR] Impossible to start boulder container in the allowed time, the Docker environment will be stopped"
echo "[ERROR] Unable to start boulder container in the allowed time, the Docker environment will be stopped"
down_environment
exit 41
fi

View File

@@ -13,7 +13,7 @@ defaultEntryPoints = ["http", "https"]
email = "test@traefik.io"
storage = "traefik/acme/account"
entryPoint = "https"
OnHostRule = true
onHostRule = true
caServer = "http://traefik.boulder.com:4001/directory"
[acme.httpChallenge]
entryPoint="http"
@@ -25,4 +25,4 @@ entryPoint="http"
endpoint = "unix:///var/run/docker.sock"
domain = "localhost.com"
watch = true
exposedbydefault = false
exposedByDefault = false

View File

@@ -0,0 +1,8 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheese-default
spec:
backend:
serviceName: stilton
servicePort: 80

View File

@@ -28,6 +28,11 @@ spec:
containers:
- image: traefik
name: traefik-ingress-lb
ports:
- name: http
containerPort: 80
- name: admin
containerPort: 8080
args:
- --api
- --kubernetes

View File

@@ -21,7 +21,6 @@ spec:
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
hostNetwork: true
containers:
- image: traefik
name: traefik-ingress-lb
@@ -31,6 +30,7 @@ spec:
hostPort: 80
- name: admin
containerPort: 8080
hostPort: 8080
securityContext:
capabilities:
drop:
@@ -57,4 +57,3 @@ spec:
- protocol: TCP
port: 8080
name: admin
type: NodePort

View File

@@ -13,11 +13,11 @@ version: '3'
services:
reverse-proxy:
image: traefik #The official Traefik docker image
command: --api --docker #Enables the web UI and tells Træfik to listen to docker
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Træfik to listen to docker
ports:
- "80:80" #The HTTP port
- "8080:8080" #The Web UI (enabled by --api)
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock #So that Traefik can listen to the Docker events
```
@@ -41,7 +41,7 @@ Edit your `docker-compose.yml` file and add the following at the end of your fil
```yaml
# ...
whoami:
image: emilevauge/whoami #A container that exposes an API to show it's IP address
image: emilevauge/whoami # A container that exposes an API to show its IP address
labels:
- "traefik.frontend.rule=Host:whoami.docker.localhost"
```
@@ -101,6 +101,7 @@ IP: 172.27.0.4
### 4 — Enjoy Træfik's Magic
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](https://docs.traefik.io/) and let Træfik work for you! Whatever your infrastructure is, there is probably [an available Træfik backend](https://docs.traefik.io/configuration/backends/available) that will do the job.
Now that you have a basic understanding of how Træfik can automatically create the routes to your services and load balance them, it might be time to dive into [the documentation](https://docs.traefik.io/) and let Træfik work for you!
Whatever your infrastructure is, there is probably [an available Træfik backend](https://docs.traefik.io/#supported-backends) that will do the job.
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](https://docs.traefik.io/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/).
Our recommendation would be to see for yourself how simple it is to enable HTTPS with [Træfik's let's encrypt integration](https://docs.traefik.io/user-guide/examples/#lets-encrypt-support) using the dedicated [user guide](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/).

477
h2c/h2c.go Normal file
View File

@@ -0,0 +1,477 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package h2c implements the h2c part of HTTP/2.
//
// The h2c protocol is the non-TLS secured version of HTTP/2 which is not
// available from net/http.
package h2c
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/textproto"
"os"
"strings"
"github.com/containous/traefik/log"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
)
var (
http2VerboseLogs bool
)
func init() {
e := os.Getenv("GODEBUG")
if strings.Contains(e, "http2debug=1") || strings.Contains(e, "http2debug=2") {
http2VerboseLogs = true
}
http2VerboseLogs = true
}
// Server implements net.Handler and enables h2c. Users who want h2c just need
// to provide an http.Server.
type Server struct {
*http.Server
}
// Serve Put a middleware around the original handler to handle h2c
func (s Server) Serve(l net.Listener) error {
originalHandler := s.Server.Handler
if originalHandler == nil {
originalHandler = http.DefaultServeMux
}
s.Server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "PRI" && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
if http2VerboseLogs {
log.Debugf("Attempting h2c with prior knowledge.")
}
conn, err := initH2CWithPriorKnowledge(w)
if err != nil {
if http2VerboseLogs {
log.Debugf("Error h2c with prior knowledge: %v", err)
}
return
}
defer conn.Close()
h2cSrv := &http2.Server{}
h2cSrv.ServeConn(conn, &http2.ServeConnOpts{Handler: originalHandler})
return
}
if conn, err := h2cUpgrade(w, r); err == nil {
defer conn.Close()
h2cSrv := &http2.Server{}
h2cSrv.ServeConn(conn, &http2.ServeConnOpts{Handler: originalHandler})
return
}
originalHandler.ServeHTTP(w, r)
})
return s.Server.Serve(l)
}
// initH2CWithPriorKnowledge implements creating a h2c connection with prior
// knowledge (Section 3.4) and creates a net.Conn suitable for http2.ServeConn.
// All we have to do is look for the client preface that is suppose to be part
// of the body, and reforward the client preface on the net.Conn this function
// creates.
func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) {
hijacker, ok := w.(http.Hijacker)
if !ok {
return nil, errors.New("hijack not supported")
}
conn, rw, err := hijacker.Hijack()
if err != nil {
return nil, fmt.Errorf("hijack failed: %v", err)
}
expectedBody := "SM\r\n\r\n"
buf := make([]byte, len(expectedBody))
n, err := io.ReadFull(rw, buf)
if err != nil {
return nil, fmt.Errorf("fail to read body: %v", err)
}
if bytes.Equal(buf[0:n], []byte(expectedBody)) {
c := &rwConn{
Conn: conn,
Reader: io.MultiReader(bytes.NewBuffer([]byte(http2.ClientPreface)), rw),
BufWriter: rw.Writer,
}
return c, nil
}
conn.Close()
if http2VerboseLogs {
log.Printf(
"Missing the request body portion of the client preface. Wanted: %v Got: %v",
[]byte(expectedBody),
buf[0:n],
)
}
return nil, errors.New("invalid client preface")
}
// drainClientPreface reads a single instance of the HTTP/2 client preface from
// the supplied reader.
func drainClientPreface(r io.Reader) error {
var buf bytes.Buffer
prefaceLen := int64(len([]byte(http2.ClientPreface)))
n, err := io.CopyN(&buf, r, prefaceLen)
if err != nil {
return err
}
if n != prefaceLen || buf.String() != http2.ClientPreface {
return fmt.Errorf("client never sent: %s", http2.ClientPreface)
}
return nil
}
// h2cUpgrade establishes a h2c connection using the HTTP/1 upgrade (Section 3.2).
func h2cUpgrade(w http.ResponseWriter, r *http.Request) (net.Conn, error) {
if !isH2CUpgrade(r.Header) {
return nil, errors.New("non-conforming h2c headers")
}
// Initial bytes we put into conn to fool http2 server
initBytes, _, err := convertH1ReqToH2(r)
if err != nil {
return nil, err
}
hijacker, ok := w.(http.Hijacker)
if !ok {
return nil, errors.New("hijack not supported")
}
conn, rw, err := hijacker.Hijack()
if err != nil {
return nil, fmt.Errorf("hijack failed: %v", err)
}
rw.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: h2c\r\n\r\n"))
rw.Flush()
// A conforming client will now send an H2 client preface which need to drain
// since we already sent this.
if err := drainClientPreface(rw); err != nil {
return nil, err
}
c := &rwConn{
Conn: conn,
Reader: io.MultiReader(initBytes, rw),
BufWriter: newSettingsAckSwallowWriter(rw.Writer),
}
return c, nil
}
// convert the data contained in the HTTP/1 upgrade request into the HTTP/2
// version in byte form.
func convertH1ReqToH2(r *http.Request) (*bytes.Buffer, []http2.Setting, error) {
h2Bytes := bytes.NewBuffer([]byte((http2.ClientPreface)))
framer := http2.NewFramer(h2Bytes, nil)
settings, err := getH2Settings(r.Header)
if err != nil {
return nil, nil, err
}
if err := framer.WriteSettings(settings...); err != nil {
return nil, nil, err
}
headerBytes, err := getH2HeaderBytes(r, getMaxHeaderTableSize(settings))
if err != nil {
return nil, nil, err
}
maxFrameSize := int(getMaxFrameSize(settings))
needOneHeader := len(headerBytes) < maxFrameSize
err = framer.WriteHeaders(http2.HeadersFrameParam{
StreamID: 1,
BlockFragment: headerBytes,
EndHeaders: needOneHeader,
})
if err != nil {
return nil, nil, err
}
for i := maxFrameSize; i < len(headerBytes); i += maxFrameSize {
if len(headerBytes)-i > maxFrameSize {
if err := framer.WriteContinuation(1,
false, // endHeaders
headerBytes[i:maxFrameSize]); err != nil {
return nil, nil, err
}
} else {
if err := framer.WriteContinuation(1,
true, // endHeaders
headerBytes[i:]); err != nil {
return nil, nil, err
}
}
}
return h2Bytes, settings, nil
}
// getMaxFrameSize returns the SETTINGS_MAX_FRAME_SIZE. If not present default
// value is 16384 as specified by RFC 7540 Section 6.5.2.
func getMaxFrameSize(settings []http2.Setting) uint32 {
for _, setting := range settings {
if setting.ID == http2.SettingMaxFrameSize {
return setting.Val
}
}
return 16384
}
// getMaxHeaderTableSize returns the SETTINGS_HEADER_TABLE_SIZE. If not present
// default value is 4096 as specified by RFC 7540 Section 6.5.2.
func getMaxHeaderTableSize(settings []http2.Setting) uint32 {
for _, setting := range settings {
if setting.ID == http2.SettingHeaderTableSize {
return setting.Val
}
}
return 4096
}
// bufWriter is a Writer interface that also has a Flush method.
type bufWriter interface {
io.Writer
Flush() error
}
// rwConn implements net.Conn but overrides Read and Write so that reads and
// writes are forwarded to the provided io.Reader and bufWriter.
type rwConn struct {
net.Conn
io.Reader
BufWriter bufWriter
}
// Read forwards reads to the underlying Reader.
func (c *rwConn) Read(p []byte) (int, error) {
return c.Reader.Read(p)
}
// Write forwards writes to the underlying bufWriter and immediately flushes.
func (c *rwConn) Write(p []byte) (int, error) {
n, err := c.BufWriter.Write(p)
if err := c.BufWriter.Flush(); err != nil {
return 0, err
}
return n, err
}
// settingsAckSwallowWriter is a writer that normally forwards bytes to it's
// underlying Writer, but swallows the first SettingsAck frame that it sees.
type settingsAckSwallowWriter struct {
Writer *bufio.Writer
buf []byte
didSwallow bool
}
// newSettingsAckSwallowWriter returns a new settingsAckSwallowWriter.
func newSettingsAckSwallowWriter(w *bufio.Writer) *settingsAckSwallowWriter {
return &settingsAckSwallowWriter{
Writer: w,
buf: make([]byte, 0),
didSwallow: false,
}
}
// Write implements io.Writer interface. Normally forwards bytes to w.Writer,
// except for the first Settings ACK frame that it sees.
func (w *settingsAckSwallowWriter) Write(p []byte) (int, error) {
if !w.didSwallow {
w.buf = append(w.buf, p...)
// Process all the frames we have collected into w.buf
for {
// Append until we get full frame header which is 9 bytes
if len(w.buf) < 9 {
break
}
// Check if we have collected a whole frame.
fh, err := http2.ReadFrameHeader(bytes.NewBuffer(w.buf))
if err != nil {
// Corrupted frame, fail current Write
return 0, err
}
fSize := fh.Length + 9
if uint32(len(w.buf)) < fSize {
// Have not collected whole frame. Stop processing buf, and withhold on
// forward bytes to w.Writer until we get the full frame.
break
}
// We have now collected a whole frame.
if fh.Type == http2.FrameSettings && fh.Flags.Has(http2.FlagSettingsAck) {
// If Settings ACK frame, do not forward to underlying writer, remove
// bytes from w.buf, and record that we have swallowed Settings Ack
// frame.
w.didSwallow = true
w.buf = w.buf[fSize:]
continue
}
// Not settings ack frame. Forward bytes to w.Writer.
if _, err := w.Writer.Write(w.buf[:fSize]); err != nil {
// Couldn't forward bytes. Fail current Write.
return 0, err
}
w.buf = w.buf[fSize:]
}
return len(p), nil
}
return w.Writer.Write(p)
}
// Flush calls w.Writer.Flush.
func (w *settingsAckSwallowWriter) Flush() error {
return w.Writer.Flush()
}
// isH2CUpgrade returns true if the header properly request an upgrade to h2c
// as specified by Section 3.2.
func isH2CUpgrade(h http.Header) bool {
return httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Upgrade")], "h2c") &&
httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Connection")], "HTTP2-Settings")
}
// getH2Settings returns the []http2.Setting that are encoded in the
// HTTP2-Settings header.
func getH2Settings(h http.Header) ([]http2.Setting, error) {
vals, ok := h[textproto.CanonicalMIMEHeaderKey("HTTP2-Settings")]
if !ok {
return nil, errors.New("missing HTTP2-Settings header")
}
if len(vals) != 1 {
return nil, fmt.Errorf("expected 1 HTTP2-Settings. Got: %v", vals)
}
settings, err := decodeSettings(vals[0])
if err != nil {
return nil, fmt.Errorf("invalid HTTP2-Settings: %q", vals[0])
}
return settings, nil
}
// decodeSettings decodes the base64url header value of the HTTP2-Settings
// header. RFC 7540 Section 3.2.1.
func decodeSettings(headerVal string) ([]http2.Setting, error) {
b, err := base64.RawURLEncoding.DecodeString(headerVal)
if err != nil {
return nil, err
}
if len(b)%6 != 0 {
return nil, err
}
settings := make([]http2.Setting, 0)
for i := 0; i < len(b)/6; i++ {
settings = append(settings, http2.Setting{
ID: http2.SettingID(binary.BigEndian.Uint16(b[i*6 : i*6+2])),
Val: binary.BigEndian.Uint32(b[i*6+2 : i*6+6]),
})
}
return settings, nil
}
// getH2HeaderBytes return the headers in r a []bytes encoded by HPACK.
func getH2HeaderBytes(r *http.Request, maxHeaderTableSize uint32) ([]byte, error) {
headerBytes := bytes.NewBuffer(nil)
hpackEnc := hpack.NewEncoder(headerBytes)
hpackEnc.SetMaxDynamicTableSize(maxHeaderTableSize)
// Section 8.1.2.3
err := hpackEnc.WriteField(hpack.HeaderField{
Name: ":method",
Value: r.Method,
})
if err != nil {
return nil, err
}
err = hpackEnc.WriteField(hpack.HeaderField{
Name: ":scheme",
Value: "http",
})
if err != nil {
return nil, err
}
err = hpackEnc.WriteField(hpack.HeaderField{
Name: ":authority",
Value: r.Host,
})
if err != nil {
return nil, err
}
path := r.URL.Path
if r.URL.RawQuery != "" {
path = strings.Join([]string{path, r.URL.RawQuery}, "?")
}
err = hpackEnc.WriteField(hpack.HeaderField{
Name: ":path",
Value: path,
})
if err != nil {
return nil, err
}
// TODO Implement Section 8.3
for header, values := range r.Header {
// Skip non h2 headers
if isNonH2Header(header) {
continue
}
for _, v := range values {
err := hpackEnc.WriteField(hpack.HeaderField{
Name: strings.ToLower(header),
Value: v,
})
if err != nil {
return nil, err
}
}
}
return headerBytes.Bytes(), nil
}
// Connection specific headers listed in RFC 7540 Section 8.1.2.2 that are not
// suppose to be transferred to HTTP/2. The Http2-Settings header is skipped
// since already use to create the HTTP/2 SETTINGS frame.
var nonH2Headers = []string{
"Connection",
"Keep-Alive",
"Proxy-Connection",
"Transfer-Encoding",
"Upgrade",
"Http2-Settings",
}
// isNonH2Header returns true if header should not be transferred to HTTP/2.
func isNonH2Header(header string) bool {
for _, nonH2h := range nonH2Headers {
if header == nonH2h {
return true
}
}
return false
}

View File

@@ -19,73 +19,82 @@ import (
var singleton *HealthCheck
var once sync.Once
// GetHealthCheck returns the health check which is guaranteed to be a singleton.
func GetHealthCheck(metrics metricsRegistry) *HealthCheck {
once.Do(func() {
singleton = newHealthCheck(metrics)
})
return singleton
// BalancerHandler includes functionality for load-balancing management.
type BalancerHandler interface {
ServeHTTP(w http.ResponseWriter, req *http.Request)
Servers() []*url.URL
RemoveServer(u *url.URL) error
UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error
}
// metricsRegistry is a local interface in the health check package, exposing only the required metrics
// necessary for the health check package. This makes it easier for the tests.
type metricsRegistry interface {
BackendServerUpGauge() metrics.Gauge
}
// Options are the public health check options.
type Options struct {
Headers map[string]string
Hostname string
Scheme string
Path string
Port int
Transport http.RoundTripper
Interval time.Duration
LB LoadBalancer
LB BalancerHandler
}
func (opt Options) String() string {
return fmt.Sprintf("[Path: %s Port: %d Interval: %s]", opt.Path, opt.Port, opt.Interval)
return fmt.Sprintf("[Hostname: %s Headers: %v Path: %s Port: %d Interval: %s]", opt.Hostname, opt.Headers, opt.Path, opt.Port, opt.Interval)
}
// BackendHealthCheck HealthCheck configuration for a backend
type BackendHealthCheck struct {
// BackendConfig HealthCheck configuration for a backend
type BackendConfig struct {
Options
name string
disabledURLs []*url.URL
requestTimeout time.Duration
}
//HealthCheck struct
func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
u := &url.URL{}
*u = *serverURL
if len(b.Scheme) > 0 {
u.Scheme = b.Scheme
}
if b.Port != 0 {
u.Host = net.JoinHostPort(u.Hostname(), strconv.Itoa(b.Port))
}
u.Path += b.Path
return http.NewRequest(http.MethodGet, u.String(), nil)
}
// this function adds additional http headers and hostname to http.request
func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
if b.Options.Hostname != "" {
req.Host = b.Options.Hostname
}
for k, v := range b.Options.Headers {
req.Header.Set(k, v)
}
return req
}
// HealthCheck struct
type HealthCheck struct {
Backends map[string]*BackendHealthCheck
Backends map[string]*BackendConfig
metrics metricsRegistry
cancel context.CancelFunc
}
// LoadBalancer includes functionality for load-balancing management.
type LoadBalancer interface {
RemoveServer(u *url.URL) error
UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error
Servers() []*url.URL
}
func newHealthCheck(metrics metricsRegistry) *HealthCheck {
return &HealthCheck{
Backends: make(map[string]*BackendHealthCheck),
metrics: metrics,
}
}
// metricsRegistry is a local interface in the healthcheck package, exposing only the required metrics
// necessary for the healthcheck package. This makes it easier for the tests.
type metricsRegistry interface {
BackendServerUpGauge() metrics.Gauge
}
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
func NewBackendHealthCheck(options Options, backendName string) *BackendHealthCheck {
return &BackendHealthCheck{
Options: options,
name: backendName,
requestTimeout: 5 * time.Second,
}
}
//SetBackendsConfiguration set backends configuration
func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendHealthCheck) {
// SetBackendsConfiguration set backends configuration
func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendConfig) {
hc.Backends = backends
if hc.cancel != nil {
hc.cancel()
@@ -101,7 +110,7 @@ func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backe
}
}
func (hc *HealthCheck) execute(ctx context.Context, backend *BackendHealthCheck) {
func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) {
log.Debugf("Initial health check for backend: %q", backend.name)
hc.checkBackend(backend)
ticker := time.NewTicker(backend.Interval)
@@ -118,7 +127,7 @@ func (hc *HealthCheck) execute(ctx context.Context, backend *BackendHealthCheck)
}
}
func (hc *HealthCheck) checkBackend(backend *BackendHealthCheck) {
func (hc *HealthCheck) checkBackend(backend *BackendConfig) {
enabledURLs := backend.LB.Servers()
var newDisabledURLs []*url.URL
for _, url := range backend.disabledURLs {
@@ -149,42 +158,55 @@ func (hc *HealthCheck) checkBackend(backend *BackendHealthCheck) {
}
}
func (backend *BackendHealthCheck) newRequest(serverURL *url.URL) (*http.Request, error) {
if backend.Port == 0 {
return http.NewRequest(http.MethodGet, serverURL.String()+backend.Path, nil)
// GetHealthCheck returns the health check which is guaranteed to be a singleton.
func GetHealthCheck(metrics metricsRegistry) *HealthCheck {
once.Do(func() {
singleton = newHealthCheck(metrics)
})
return singleton
}
func newHealthCheck(metrics metricsRegistry) *HealthCheck {
return &HealthCheck{
Backends: make(map[string]*BackendConfig),
metrics: metrics,
}
}
// copy the url and add the port to the host
u := &url.URL{}
*u = *serverURL
u.Host = net.JoinHostPort(u.Hostname(), strconv.Itoa(backend.Port))
u.Path = u.Path + backend.Path
return http.NewRequest(http.MethodGet, u.String(), nil)
// NewBackendConfig Instantiate a new BackendConfig
func NewBackendConfig(options Options, backendName string) *BackendConfig {
return &BackendConfig{
Options: options,
name: backendName,
requestTimeout: 5 * time.Second,
}
}
// checkHealth returns a nil error in case it was successful and otherwise
// a non-nil error with a meaningful description why the health check failed.
func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) error {
client := http.Client{
Timeout: backend.requestTimeout,
Transport: backend.Options.Transport,
}
func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
req, err := backend.newRequest(serverURL)
if err != nil {
return fmt.Errorf("failed to create HTTP request: %s", err)
}
resp, err := client.Do(req)
if err == nil {
defer resp.Body.Close()
req = backend.addHeadersAndHost(req)
client := http.Client{
Timeout: backend.requestTimeout,
Transport: backend.Options.Transport,
}
switch {
case err != nil:
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("HTTP request failed: %s", err)
case resp.StatusCode != http.StatusOK:
return fmt.Errorf("received non-200 status code: %v", resp.StatusCode)
}
defer resp.Body.Close()
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("received error status code: %v", resp.StatusCode)
}
return nil
}

View File

@@ -10,6 +10,8 @@ import (
"time"
"github.com/containous/traefik/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vulcand/oxy/roundrobin"
)
@@ -17,64 +19,81 @@ const healthCheckInterval = 100 * time.Millisecond
type testHandler struct {
done func()
healthSequence []bool
healthSequence []int
}
func TestSetBackendsConfiguration(t *testing.T) {
tests := []struct {
desc string
startHealthy bool
healthSequence []bool
wantNumRemovedServers int
wantNumUpsertedServers int
wantGaugeValue float64
testCases := []struct {
desc string
startHealthy bool
healthSequence []int
expectedNumRemovedServers int
expectedNumUpsertedServers int
expectedGaugeValue float64
}{
{
desc: "healthy server staying healthy",
startHealthy: true,
healthSequence: []bool{true},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 0,
wantGaugeValue: 1,
desc: "healthy server staying healthy",
startHealthy: true,
healthSequence: []int{http.StatusOK},
expectedNumRemovedServers: 0,
expectedNumUpsertedServers: 0,
expectedGaugeValue: 1,
},
{
desc: "healthy server becoming sick",
startHealthy: true,
healthSequence: []bool{false},
wantNumRemovedServers: 1,
wantNumUpsertedServers: 0,
wantGaugeValue: 0,
desc: "healthy server staying healthy (StatusNoContent)",
startHealthy: true,
healthSequence: []int{http.StatusNoContent},
expectedNumRemovedServers: 0,
expectedNumUpsertedServers: 0,
expectedGaugeValue: 1,
},
{
desc: "sick server becoming healthy",
startHealthy: false,
healthSequence: []bool{true},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 1,
wantGaugeValue: 1,
desc: "healthy server staying healthy (StatusPermanentRedirect)",
startHealthy: true,
healthSequence: []int{http.StatusPermanentRedirect},
expectedNumRemovedServers: 0,
expectedNumUpsertedServers: 0,
expectedGaugeValue: 1,
},
{
desc: "sick server staying sick",
startHealthy: false,
healthSequence: []bool{false},
wantNumRemovedServers: 0,
wantNumUpsertedServers: 0,
wantGaugeValue: 0,
desc: "healthy server becoming sick",
startHealthy: true,
healthSequence: []int{http.StatusServiceUnavailable},
expectedNumRemovedServers: 1,
expectedNumUpsertedServers: 0,
expectedGaugeValue: 0,
},
{
desc: "healthy server toggling to sick and back to healthy",
startHealthy: true,
healthSequence: []bool{false, true},
wantNumRemovedServers: 1,
wantNumUpsertedServers: 1,
wantGaugeValue: 1,
desc: "sick server becoming healthy",
startHealthy: false,
healthSequence: []int{http.StatusOK},
expectedNumRemovedServers: 0,
expectedNumUpsertedServers: 1,
expectedGaugeValue: 1,
},
{
desc: "sick server staying sick",
startHealthy: false,
healthSequence: []int{http.StatusServiceUnavailable},
expectedNumRemovedServers: 0,
expectedNumUpsertedServers: 0,
expectedGaugeValue: 0,
},
{
desc: "healthy server toggling to sick and back to healthy",
startHealthy: true,
healthSequence: []int{http.StatusServiceUnavailable, http.StatusOK},
expectedNumRemovedServers: 1,
expectedNumUpsertedServers: 1,
expectedGaugeValue: 1,
},
}
for _, test := range tests {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
// The context is passed to the health check and canonically cancelled by
// the test server once all expected requests have been received.
ctx, cancel := context.WithCancel(context.Background())
@@ -83,11 +102,12 @@ func TestSetBackendsConfiguration(t *testing.T) {
defer ts.Close()
lb := &testLoadBalancer{RWMutex: &sync.RWMutex{}}
backend := NewBackendHealthCheck(Options{
backend := NewBackendConfig(Options{
Path: "/path",
Interval: healthCheckInterval,
LB: lb,
}, "backendName")
serverURL := testhelpers.MustParseURL(ts.URL)
if test.startHealthy {
lb.servers = append(lb.servers, serverURL)
@@ -97,11 +117,13 @@ func TestSetBackendsConfiguration(t *testing.T) {
collectingMetrics := testhelpers.NewCollectingHealthCheckMetrics()
check := HealthCheck{
Backends: make(map[string]*BackendHealthCheck),
Backends: make(map[string]*BackendConfig),
metrics: collectingMetrics,
}
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
check.execute(ctx, backend)
wg.Done()
@@ -119,83 +141,157 @@ func TestSetBackendsConfiguration(t *testing.T) {
lb.Lock()
defer lb.Unlock()
if lb.numRemovedServers != test.wantNumRemovedServers {
t.Errorf("got %d removed servers, wanted %d", lb.numRemovedServers, test.wantNumRemovedServers)
}
if lb.numUpsertedServers != test.wantNumUpsertedServers {
t.Errorf("got %d upserted servers, wanted %d", lb.numUpsertedServers, test.wantNumUpsertedServers)
}
if collectingMetrics.Gauge.GaugeValue != test.wantGaugeValue {
t.Errorf("got %v ServerUp Gauge, want %v", collectingMetrics.Gauge.GaugeValue, test.wantGaugeValue)
}
assert.Equal(t, test.expectedNumRemovedServers, lb.numRemovedServers, "removed servers")
assert.Equal(t, test.expectedNumUpsertedServers, lb.numUpsertedServers, "upserted servers")
assert.Equal(t, test.expectedGaugeValue, collectingMetrics.Gauge.GaugeValue, "ServerUp Gauge")
})
}
}
func TestNewRequest(t *testing.T) {
tests := []struct {
desc string
host string
port int
path string
expected string
testCases := []struct {
desc string
serverURL string
options Options
expected string
}{
{
desc: "no port override",
host: "backend1:80",
port: 0,
path: "/test",
desc: "no port override",
serverURL: "http://backend1:80",
options: Options{
Path: "/test",
Port: 0,
},
expected: "http://backend1:80/test",
},
{
desc: "port override",
host: "backend2:80",
port: 8080,
path: "/test",
desc: "port override",
serverURL: "http://backend2:80",
options: Options{
Path: "/test",
Port: 8080,
},
expected: "http://backend2:8080/test",
},
{
desc: "no port override with no port in host",
host: "backend1",
port: 0,
path: "/health",
desc: "no port override with no port in server URL",
serverURL: "http://backend1",
options: Options{
Path: "/health",
Port: 0,
},
expected: "http://backend1/health",
},
{
desc: "port override with no port in host",
host: "backend2",
port: 8080,
path: "/health",
desc: "port override with no port in server URL",
serverURL: "http://backend2",
options: Options{
Path: "/health",
Port: 8080,
},
expected: "http://backend2:8080/health",
},
{
desc: "scheme override",
serverURL: "https://backend1:80",
options: Options{
Scheme: "http",
Path: "/test",
Port: 0,
},
expected: "http://backend1:80/test",
},
}
for _, test := range tests {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
backend := NewBackendHealthCheck(
Options{
Path: test.path,
Port: test.port,
}, "backendName")
u := &url.URL{
Scheme: "http",
Host: test.host,
}
backend := NewBackendConfig(test.options, "backendName")
u, err := url.Parse(test.serverURL)
require.NoError(t, err)
req, err := backend.newRequest(u)
if err != nil {
t.Fatalf("failed to create new backend request: %s", err)
}
require.NoError(t, err, "failed to create new backend request")
actual := req.URL.String()
if actual != test.expected {
t.Fatalf("got %s for healthcheck URL, wanted %s", actual, test.expected)
}
assert.Equal(t, test.expected, req.URL.String())
})
}
}
func TestAddHeadersAndHost(t *testing.T) {
testCases := []struct {
desc string
serverURL string
options Options
expectedHostname string
expectedHeader string
}{
{
desc: "override hostname",
serverURL: "http://backend1:80",
options: Options{
Hostname: "myhost",
Path: "/",
},
expectedHostname: "myhost",
expectedHeader: "",
},
{
desc: "not override hostname",
serverURL: "http://backend1:80",
options: Options{
Hostname: "",
Path: "/",
},
expectedHostname: "backend1:80",
expectedHeader: "",
},
{
desc: "custom header",
serverURL: "http://backend1:80",
options: Options{
Headers: map[string]string{"Custom-Header": "foo"},
Hostname: "",
Path: "/",
},
expectedHostname: "backend1:80",
expectedHeader: "foo",
},
{
desc: "custom header with hostname override",
serverURL: "http://backend1:80",
options: Options{
Headers: map[string]string{"Custom-Header": "foo"},
Hostname: "myhost",
Path: "/",
},
expectedHostname: "myhost",
expectedHeader: "foo",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
backend := NewBackendConfig(test.options, "backendName")
u, err := url.Parse(test.serverURL)
require.NoError(t, err)
req, err := backend.newRequest(u)
require.NoError(t, err, "failed to create new backend request")
req = backend.addHeadersAndHost(req)
assert.Equal(t, "http://backend1:80/", req.URL.String())
assert.Equal(t, test.expectedHostname, req.Host)
assert.Equal(t, test.expectedHeader, req.Header.Get("Custom-Header"))
})
}
}
@@ -209,6 +305,10 @@ type testLoadBalancer struct {
servers []*url.URL
}
func (lb *testLoadBalancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// noop
}
func (lb *testLoadBalancer) RemoveServer(u *url.URL) error {
lb.Lock()
defer lb.Unlock()
@@ -241,7 +341,7 @@ func (lb *testLoadBalancer) removeServer(u *url.URL) {
lb.servers = append(lb.servers[:i], lb.servers[i+1:]...)
}
func newTestServer(done func(), healthSequence []bool) *httptest.Server {
func newTestServer(done func(), healthSequence []int) *httptest.Server {
handler := &testHandler{
done: done,
healthSequence: healthSequence,
@@ -249,21 +349,14 @@ func newTestServer(done func(), healthSequence []bool) *httptest.Server {
return httptest.NewServer(handler)
}
// ServeHTTP returns 200 or 503 HTTP response codes depending on whether the
// current request is marked as healthy or not.
// It calls the given 'done' function once all request health indicators have
// been depleted.
// ServeHTTP returns HTTP response codes following a status sequences.
// It calls the given 'done' function once all request health indicators have been depleted.
func (th *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(th.healthSequence) == 0 {
panic("received unexpected request")
}
healthy := th.healthSequence[0]
if healthy {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
w.WriteHeader(th.healthSequence[0])
th.healthSequence = th.healthSequence[1:]
if len(th.healthSequence) == 0 {

Some files were not shown because too many files have changed in this diff Show More