forked from Ivasoft/traefik
Compare commits
119 Commits
v1.5.0-rc2
...
v1.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
422109b82f | ||
|
|
c864a7297b | ||
|
|
8da038041d | ||
|
|
dd954f3c0a | ||
|
|
db483e9d34 | ||
|
|
700b7a1b51 | ||
|
|
ed65d00574 | ||
|
|
f460c1990e | ||
|
|
83381e99cf | ||
|
|
31550fd2c9 | ||
|
|
ba046b4d3a | ||
|
|
d675d46930 | ||
|
|
7ea76929d4 | ||
|
|
f98c537ec2 | ||
|
|
083bde64ee | ||
|
|
45fe218ee2 | ||
|
|
d54777236c | ||
|
|
4f3b06472b | ||
|
|
52bad03c8d | ||
|
|
2fde3e8679 | ||
|
|
1e71f52b72 | ||
|
|
2b1d2853cd | ||
|
|
f07e8f58e6 | ||
|
|
7b19cb5631 | ||
|
|
dbd173b4e4 | ||
|
|
85cfd87c44 | ||
|
|
c867f48f11 | ||
|
|
514f9a7215 | ||
|
|
0b0380b690 | ||
|
|
4d0c8c189a | ||
|
|
afe4c307f9 | ||
|
|
ce3a0fdd46 | ||
|
|
203a5c5c48 | ||
|
|
be4aeaacde | ||
|
|
26dc2f4d61 | ||
|
|
6aac78fc36 | ||
|
|
f6c53f0450 | ||
|
|
54e09b98c7 | ||
|
|
4eebaa1a80 | ||
|
|
cb9bf3ce68 | ||
|
|
49a8cb76f5 | ||
|
|
bf12306f17 | ||
|
|
323b8237a0 | ||
|
|
039ccaf4f1 | ||
|
|
4afb39778a | ||
|
|
751781a3b7 | ||
|
|
f5d150c3b4 | ||
|
|
ae9342208e | ||
|
|
3040d9df0d | ||
|
|
00e0571811 | ||
|
|
bfb07746fe | ||
|
|
171cda6186 | ||
|
|
4cc17e112f | ||
|
|
b6af61fa6e | ||
|
|
4e07d92190 | ||
|
|
fc00e1c228 | ||
|
|
ae34486b57 | ||
|
|
d7b513e9aa | ||
|
|
d8297a055a | ||
|
|
ced5aa5dc6 | ||
|
|
adfa3f795c | ||
|
|
fe426f6fb2 | ||
|
|
3e439cc39b | ||
|
|
56c0634918 | ||
|
|
bcadd68904 | ||
|
|
9790aa91fe | ||
|
|
5316b412d2 | ||
|
|
b5ee5c34f2 | ||
|
|
8239e04a19 | ||
|
|
e2c5f3712f | ||
|
|
d0f3ad6024 | ||
|
|
044d87d96d | ||
|
|
d88554fa92 | ||
|
|
e74a20de24 | ||
|
|
7c227392fa | ||
|
|
8a697f7a39 | ||
|
|
60fd26e0b7 | ||
|
|
acd0c1bcd5 | ||
|
|
22bdbd2498 | ||
|
|
287fb78654 | ||
|
|
5b24403c8e | ||
|
|
e83599dd08 | ||
|
|
f30ad20c9b | ||
|
|
01e17b6c3e | ||
|
|
3e13ebec93 | ||
|
|
23c1a9ca8e | ||
|
|
741c739ef1 | ||
|
|
52f16e11a8 | ||
|
|
0ee6973e2f | ||
|
|
4819974a1c | ||
|
|
e8e8b41eed | ||
|
|
7d23d3c0a4 | ||
|
|
718fc7a79d | ||
|
|
bfd142b13b | ||
|
|
75533b2beb | ||
|
|
9a7821b8fa | ||
|
|
e8333883df | ||
|
|
1e44e339ad | ||
|
|
89a79d0f1b | ||
|
|
9e41485ff1 | ||
|
|
3c7c6c4d9f | ||
|
|
cd1b3904da | ||
|
|
b23b2611b3 | ||
|
|
877770f7cf | ||
|
|
3142a4f4b3 | ||
|
|
b4dc96527d | ||
|
|
35b5ca4c63 | ||
|
|
daf3023b02 | ||
|
|
b17d5b80b8 | ||
|
|
48b4eb5c0d | ||
|
|
7ecd6d20ba | ||
|
|
bddad57a7b | ||
|
|
799136a714 | ||
|
|
350d61b4a6 | ||
|
|
b6f5a66fab | ||
|
|
b0c12e2422 | ||
|
|
623a7dc7e6 | ||
|
|
709c7e5707 | ||
|
|
ee04f52a16 |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -22,7 +22,7 @@ If you intend to ask a support question: DO NOT FILE AN ISSUE.
|
||||
|
||||
HOW TO WRITE A GOOD ISSUE?
|
||||
|
||||
- Respect the issue template as more as possible.
|
||||
- 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.
|
||||
|
||||
68
.github/ISSUE_TEMPLATE/bugs.md
vendored
Normal file
68
.github/ISSUE_TEMPLATE/bugs.md
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<!--
|
||||
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 you’re 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 mode (`--debug` switch)
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
32
.github/ISSUE_TEMPLATE/features.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/features.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
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 you’re 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
|
||||
|
||||
-->
|
||||
|
||||
7
.github/PULL_REQUEST_TEMPLATE/mergeback.md
vendored
Normal file
7
.github/PULL_REQUEST_TEMPLATE/mergeback.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
### What does this PR do?
|
||||
|
||||
Merge v{{.Version}} into master
|
||||
|
||||
### Motivation
|
||||
|
||||
Be sync.
|
||||
7
.github/PULL_REQUEST_TEMPLATE/release.md
vendored
Normal file
7
.github/PULL_REQUEST_TEMPLATE/release.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
### What does this PR do?
|
||||
|
||||
Prepare release v{{.Version}}.
|
||||
|
||||
### Motivation
|
||||
|
||||
Create a new release.
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,4 +11,4 @@
|
||||
*.log
|
||||
*.exe
|
||||
.DS_Store
|
||||
/example/acme/acme.json
|
||||
/examples/acme/acme.json
|
||||
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,6 +1,9 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
git:
|
||||
depth: false
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
@@ -21,22 +24,16 @@ before_deploy:
|
||||
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;
|
||||
pip install --user -r requirements.txt;
|
||||
make -j${N_MAKE_JOBS} crossbinary-parallel;
|
||||
make image-dirty;
|
||||
mkdocs build --clean;
|
||||
tar cfz dist/traefik-${VERSION}.src.tar.gz --exclude-vcs --exclude dist .;
|
||||
make image;
|
||||
if [ "$TRAVIS_TAG" ]; then
|
||||
make -j${N_MAKE_JOBS} crossbinary-parallel;
|
||||
tar cfz dist/traefik-${VERSION}.src.tar.gz --exclude-vcs --exclude dist .;
|
||||
fi;
|
||||
curl -sI https://github.com/containous/structor/releases/latest | grep -Fi Location | tr -d '\r' | sed "s/tag/download/g" | awk -F " " '{ print $2 "/structor_linux-amd64"}' | wget --output-document=$GOPATH/bin/structor -i -;
|
||||
chmod +x $GOPATH/bin/structor;
|
||||
structor -o containous -r traefik --dockerfile-url="https://raw.githubusercontent.com/containous/traefik/master/docs.Dockerfile" --menu.js-url="https://raw.githubusercontent.com/containous/structor/master/traefik-menu.js.gotmpl" --exp-branch=master --debug;
|
||||
fi
|
||||
deploy:
|
||||
- provider: pages
|
||||
edge: true
|
||||
github_token: ${GITHUB_TOKEN}
|
||||
local_dir: site
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
tags: true
|
||||
condition: ${TRAVIS_TAG} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$
|
||||
- provider: releases
|
||||
api_key: ${GITHUB_TOKEN}
|
||||
file: dist/traefik*
|
||||
@@ -56,3 +53,11 @@ deploy:
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
- provider: pages
|
||||
edge: true
|
||||
github_token: ${GITHUB_TOKEN}
|
||||
local_dir: site
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
all_branches: true
|
||||
|
||||
301
CHANGELOG.md
301
CHANGELOG.md
@@ -1,5 +1,306 @@
|
||||
# Change Log
|
||||
|
||||
## [v1.5.3](https://github.com/containous/traefik/tree/v1.5.3) (2018-02-27)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.2...v1.5.3)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Check all the C/N and SANs of provided certificates before generating ACME certificates ([#2913](https://github.com/containous/traefik/pull/2913) by [nmengin](https://github.com/nmengin))
|
||||
- **[docker/swarm]** Empty IP address when use endpoint mode dnsrr ([#2887](https://github.com/containous/traefik/pull/2887) by [mmatur](https://github.com/mmatur))
|
||||
- **[middleware]** Infinite entry point redirection. ([#2929](https://github.com/containous/traefik/pull/2929) by [ldez](https://github.com/ldez))
|
||||
- **[provider]** Isolate backend with same name on different provider ([#2862](https://github.com/containous/traefik/pull/2862) by [Juliens](https://github.com/Juliens))
|
||||
- **[tls]** Starting Træfik even if TLS certificates are in error ([#2909](https://github.com/containous/traefik/pull/2909) by [nmengin](https://github.com/nmengin))
|
||||
- **[tls]** Add DEBUG log when no provided certificate can check a domain ([#2938](https://github.com/containous/traefik/pull/2938) by [nmengin](https://github.com/nmengin))
|
||||
- **[webui]** Smooth dashboard refresh. ([#2871](https://github.com/containous/traefik/pull/2871) by [ldez](https://github.com/ldez))
|
||||
- Fix Duration JSON unmarshal ([#2935](https://github.com/containous/traefik/pull/2935) by [ldez](https://github.com/ldez))
|
||||
- Default value for lifecycle ([#2934](https://github.com/containous/traefik/pull/2934) by [Juliens](https://github.com/Juliens))
|
||||
- Check ping configuration. ([#2852](https://github.com/containous/traefik/pull/2852) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[docker]** it's -> its ([#2901](https://github.com/containous/traefik/pull/2901) by [piec](https://github.com/piec))
|
||||
- **[tls]** Fix doc cipher suites ([#2894](https://github.com/containous/traefik/pull/2894) by [emilevauge](https://github.com/emilevauge))
|
||||
- Add a CLI help command for Docker. ([#2921](https://github.com/containous/traefik/pull/2921) by [ldez](https://github.com/ldez))
|
||||
- Fix traffic pronounce dead link ([#2870](https://github.com/containous/traefik/pull/2870) by [emilevauge](https://github.com/emilevauge))
|
||||
- Update documentation on onHostRule, ping examples, and web deprecation ([#2863](https://github.com/containous/traefik/pull/2863) by [Juliens](https://github.com/Juliens))
|
||||
|
||||
## [v1.5.2](https://github.com/containous/traefik/tree/v1.5.2) (2018-02-12)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.1...v1.5.2)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,cluster,kv]** Compress ACME certificates in KV stores. ([#2814](https://github.com/containous/traefik/pull/2814) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme]** Traefik still start when Let's encrypt is down ([#2794](https://github.com/containous/traefik/pull/2794) by [Juliens](https://github.com/Juliens))
|
||||
- **[docker]** Fix dnsrr endpoint mode excluded when not using swarm LB ([#2795](https://github.com/containous/traefik/pull/2795) by [mmatur](https://github.com/mmatur))
|
||||
- **[eureka]** Continue refresh the configuration after a failure. ([#2838](https://github.com/containous/traefik/pull/2838) by [ldez](https://github.com/ldez))
|
||||
- **[logs]** Reduce oxy round trip logs to debug. ([#2821](https://github.com/containous/traefik/pull/2821) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[websocket]** Fix goroutine leaks in websocket ([#2825](https://github.com/containous/traefik/pull/2825) by [Juliens](https://github.com/Juliens))
|
||||
- Hide the pflag error when displaying help. ([#2800](https://github.com/containous/traefik/pull/2800) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[docker]** Explain how to write entrypoints definition in a compose file ([#2834](https://github.com/containous/traefik/pull/2834) by [mmatur](https://github.com/mmatur))
|
||||
- **[docker]** Fix typo ([#2813](https://github.com/containous/traefik/pull/2813) by [uschtwill](https://github.com/uschtwill))
|
||||
- **[k8s]** typo in "i"ngress annotations. ([#2780](https://github.com/containous/traefik/pull/2780) by [RRAlex](https://github.com/RRAlex))
|
||||
- Clarify how setting a frontend priority works ([#2818](https://github.com/containous/traefik/pull/2818) by [sirlatrom](https://github.com/sirlatrom))
|
||||
- Fixed typo. ([#2811](https://github.com/containous/traefik/pull/2811) by [sonus21](https://github.com/sonus21))
|
||||
- Docs: regex+replacement hints for URL rewriting ([#2802](https://github.com/containous/traefik/pull/2802) by [djeeg](https://github.com/djeeg))
|
||||
- Add documentation about entry points definition with CLI. ([#2798](https://github.com/containous/traefik/pull/2798) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.5.1](https://github.com/containous/traefik/tree/v1.5.1) (2018-01-29)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0...v1.5.1)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Handle undefined entrypoint on ACME config and frontend config ([#2756](https://github.com/containous/traefik/pull/2756) by [Juliens](https://github.com/Juliens))
|
||||
- **[k8s]** Fix the k8s redirection template. ([#2748](https://github.com/containous/traefik/pull/2748) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** Change gzipwriter receiver to implement CloseNotifier ([#2766](https://github.com/containous/traefik/pull/2766) by [Juliens](https://github.com/Juliens))
|
||||
- **[tls]** Fix domain names in dynamic TLS configuration ([#2768](https://github.com/containous/traefik/pull/2768) by [nmengin](https://github.com/nmengin))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Add note on redirect for ACME http challenge ([#2767](https://github.com/containous/traefik/pull/2767) by [Juliens](https://github.com/Juliens))
|
||||
- **[file]** Enhance file provider documentation. ([#2777](https://github.com/containous/traefik/pull/2777) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.5.0](https://github.com/containous/traefik/tree/v1.5.0) (2018-01-23)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.4.0-rc1...v1.5.0)
|
||||
|
||||
**Enhancements:**
|
||||
- **[acme,tls]** Rename TLSConfigurations to TLS. ([#2744](https://github.com/containous/traefik/pull/2744) by [ldez](https://github.com/ldez))
|
||||
- **[acme,provider,docker,tls]** Make the TLS certificates management dynamic. ([#2233](https://github.com/containous/traefik/pull/2233) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme]** Add Let's Encrypt HTTP Challenge ([#2701](https://github.com/containous/traefik/pull/2701) by [Juliens](https://github.com/Juliens))
|
||||
- **[acme]** Update github.com/xenolf/lego to 0.4.1 ([#2304](https://github.com/containous/traefik/pull/2304) by [oldmantaiter](https://github.com/oldmantaiter))
|
||||
- **[api,healthcheck,metrics,provider,webui]** Split Web into API/Dashboard, ping, metric and Rest Provider ([#2335](https://github.com/containous/traefik/pull/2335) by [Juliens](https://github.com/Juliens))
|
||||
- **[authentication]** Pass through certain forward auth negative response headers ([#2127](https://github.com/containous/traefik/pull/2127) by [wheresmysocks](https://github.com/wheresmysocks))
|
||||
- **[cluster,consul,file]** Add file to storeconfig ([#2419](https://github.com/containous/traefik/pull/2419) by [emilevauge](https://github.com/emilevauge))
|
||||
- **[cluster,provider]** Support Etcd v3, enhance KV support ([#2407](https://github.com/containous/traefik/pull/2407) by [nmengin](https://github.com/nmengin))
|
||||
- **[docker,k8s,rancher,webui]** Redirect to another entryPoint per frontend ([#2133](https://github.com/containous/traefik/pull/2133) by [SantoDE](https://github.com/SantoDE))
|
||||
- **[docker,k8s,rancher]** Support regex redirect by frontend ([#2570](https://github.com/containous/traefik/pull/2570) by [ldez](https://github.com/ldez))
|
||||
- **[docker]** Add Custom header parsing to Docker Provider ([#2030](https://github.com/containous/traefik/pull/2030) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[docker]** Docker labels ([#2473](https://github.com/containous/traefik/pull/2473) by [ldez](https://github.com/ldez))
|
||||
- **[docker]** Add docker security headers via labels ([#2334](https://github.com/containous/traefik/pull/2334) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[docker]** Use Node IP in Swarm Standalone with "host" NetworkMode ([#2274](https://github.com/containous/traefik/pull/2274) by [BlakeMesdag](https://github.com/BlakeMesdag))
|
||||
- **[ecs]** ECS provider refactoring ([#2050](https://github.com/containous/traefik/pull/2050) by [mmatur](https://github.com/mmatur))
|
||||
- **[ecs]** Add health check label to ECS ([#2421](https://github.com/containous/traefik/pull/2421) by [oldmantaiter](https://github.com/oldmantaiter))
|
||||
- **[ecs]** Support Host NetworkMode for ECS provider ([#2320](https://github.com/containous/traefik/pull/2320) by [FriggaHel](https://github.com/FriggaHel))
|
||||
- **[etcd]** Manage certificates dynamically in kv store ([#2411](https://github.com/containous/traefik/pull/2411) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- **[healthcheck]** Use health check for systemd watchdog ([#2283](https://github.com/containous/traefik/pull/2283) by [guilhem](https://github.com/guilhem))
|
||||
- **[k8s]** Kubernetes security header annotations ([#2460](https://github.com/containous/traefik/pull/2460) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[k8s]** Add labels for `traefik.frontend.entryPoints` & `PassTLSCert` to Kubernetes ([#2324](https://github.com/containous/traefik/pull/2324) by [ryarnyah](https://github.com/ryarnyah))
|
||||
- **[k8s]** Only listen to configured k8s namespaces. ([#1895](https://github.com/containous/traefik/pull/1895) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[logs,middleware,consul,docker]** Use constants from http package. ([#2425](https://github.com/containous/traefik/pull/2425) by [ldez](https://github.com/ldez))
|
||||
- **[logs]** Add json format support for Traefik logs ([#2056](https://github.com/containous/traefik/pull/2056) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[marathon]** Marathon constraints filtering ([#2388](https://github.com/containous/traefik/pull/2388) by [aantono](https://github.com/aantono))
|
||||
- **[marathon]** Remove unused lightMarathonClient. ([#2383](https://github.com/containous/traefik/pull/2383) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[metrics]** Add InfluxDB support for traefik metrics ([#2289](https://github.com/containous/traefik/pull/2289) by [adityacs](https://github.com/adityacs))
|
||||
- **[middleware]** Added ReplacePathRegex middleware ([#2033](https://github.com/containous/traefik/pull/2033) by [Tiscs](https://github.com/Tiscs))
|
||||
- **[middleware]** Fix custom headers replacement ([#2455](https://github.com/containous/traefik/pull/2455) by [mmatur](https://github.com/mmatur))
|
||||
- **[oxy]** Resync oxy with original repository ([#2451](https://github.com/containous/traefik/pull/2451) by [Juliens](https://github.com/Juliens))
|
||||
- **[provider]** Support template as raw string. ([#2413](https://github.com/containous/traefik/pull/2413) by [ldez](https://github.com/ldez))
|
||||
- **[rancher]** Run Rancher tests cases in parallel. ([#2424](https://github.com/containous/traefik/pull/2424) by [ldez](https://github.com/ldez))
|
||||
- **[rancher]** Update Rancher API integration to go-rancher client v2. ([#2291](https://github.com/containous/traefik/pull/2291) by [rawmind0](https://github.com/rawmind0))
|
||||
- **[servicefabric]** Add Service Fabric Provider ([#2117](https://github.com/containous/traefik/pull/2117) by [lawrencegripper](https://github.com/lawrencegripper))
|
||||
- **[tls]** Allow adding optional Client CA files ([#2306](https://github.com/containous/traefik/pull/2306) by [nmengin](https://github.com/nmengin))
|
||||
- **[websocket]** Add tests for websocket headers ([#2379](https://github.com/containous/traefik/pull/2379) by [Juliens](https://github.com/Juliens))
|
||||
- Upgrade libkermit/compose version ([#2071](https://github.com/containous/traefik/pull/2071) by [nmengin](https://github.com/nmengin))
|
||||
- Add proxy protocol tests ([#2325](https://github.com/containous/traefik/pull/2325) by [emilevauge](https://github.com/emilevauge))
|
||||
- Register pprof handlers. ([#2428](https://github.com/containous/traefik/pull/2428) by [timoreimann](https://github.com/timoreimann))
|
||||
- Rate limiting for frontends ([#2034](https://github.com/containous/traefik/pull/2034) by [bparli](https://github.com/bparli))
|
||||
- Stats collection. ([#2447](https://github.com/containous/traefik/pull/2447) by [ldez](https://github.com/ldez))
|
||||
- Add request accepting grace period delaying graceful shutdown. ([#1971](https://github.com/containous/traefik/pull/1971) by [timoreimann](https://github.com/timoreimann))
|
||||
- Put subcommand in dedicated files. ([#2265](https://github.com/containous/traefik/pull/2265) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,docker]** Modify ACME configuration migration into KV store ([#2598](https://github.com/containous/traefik/pull/2598) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme,logs]** Modify DEBUG messages to get ACME certificates ([#2685](https://github.com/containous/traefik/pull/2685) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme]** Modify the ACME renewing logs level ([#2520](https://github.com/containous/traefik/pull/2520) by [nmengin](https://github.com/nmengin))
|
||||
- **[acme]** ACME and corporate proxy. ([#2738](https://github.com/containous/traefik/pull/2738) by [ldez](https://github.com/ldez))
|
||||
- **[acme]** Challenge HTTP must ignore deprecated web.path option ([#2719](https://github.com/containous/traefik/pull/2719) by [Juliens](https://github.com/Juliens))
|
||||
- **[api]** Fix pprof route order. ([#2523](https://github.com/containous/traefik/pull/2523) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[authentication,middleware]** Fix concurrent map writes on digest auth ([#2695](https://github.com/containous/traefik/pull/2695) by [mmatur](https://github.com/mmatur))
|
||||
- **[consulcatalog]** Use prefix for sticky and stickiness tags. ([#2624](https://github.com/containous/traefik/pull/2624) by [ldez](https://github.com/ldez))
|
||||
- **[consulcatalog]** Fix bad Træfik update on Consul Catalog ([#2573](https://github.com/containous/traefik/pull/2573) by [mmatur](https://github.com/mmatur))
|
||||
- **[consulcatalog]** Reload configuration when port change for one service ([#2574](https://github.com/containous/traefik/pull/2574) by [mmatur](https://github.com/mmatur))
|
||||
- **[docker,k8s]** Fix Labels/annotation logs and values. ([#2488](https://github.com/containous/traefik/pull/2488) by [ldez](https://github.com/ldez))
|
||||
- **[docker,k8s]** Change custom headers separator ([#2509](https://github.com/containous/traefik/pull/2509) by [ldez](https://github.com/ldez))
|
||||
- **[docker]** Fix empty IP for backend when dnsrr in Docker swarm mode ([#2490](https://github.com/containous/traefik/pull/2490) by [mmatur](https://github.com/mmatur))
|
||||
- **[docker]** Quote template strings ([#2496](https://github.com/containous/traefik/pull/2496) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[docker]** Return errors from Docker client.Events ([#2689](https://github.com/containous/traefik/pull/2689) by [BlakeMesdag](https://github.com/BlakeMesdag))
|
||||
- **[docker]** Typo in Docker template. ([#2692](https://github.com/containous/traefik/pull/2692) by [ldez](https://github.com/ldez))
|
||||
- **[ecs]** Add missing functions for ECS template ([#2312](https://github.com/containous/traefik/pull/2312) by [oldmantaiter](https://github.com/oldmantaiter))
|
||||
- **[file,tls]** Send empty configuration from file provider ([#2609](https://github.com/containous/traefik/pull/2609) by [nmengin](https://github.com/nmengin))
|
||||
- **[healthcheck]** Fix health check when web is not specified ([#2529](https://github.com/containous/traefik/pull/2529) by [Juliens](https://github.com/Juliens))
|
||||
- **[k8s]** Reduce logs with new Kubernetes security annotations ([#2506](https://github.com/containous/traefik/pull/2506) by [ldez](https://github.com/ldez))
|
||||
- **[k8s]** Add missing entry points template. ([#2594](https://github.com/containous/traefik/pull/2594) by [ldez](https://github.com/ldez))
|
||||
- **[kv]** Fix stickiness bug due to template syntax error ([#2591](https://github.com/containous/traefik/pull/2591) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- **[kv]** List entries parsing. ([#2669](https://github.com/containous/traefik/pull/2669) by [ldez](https://github.com/ldez))
|
||||
- **[logs]** Fix traefik logs to behave like configured ([#2176](https://github.com/containous/traefik/pull/2176) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[marathon]** Update go-marathon ([#2585](https://github.com/containous/traefik/pull/2585) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[mesos]** Mesos: Use slave.PID.Host as task SlaveIP. ([#2590](https://github.com/containous/traefik/pull/2590) by [nemosupremo](https://github.com/nemosupremo))
|
||||
- **[metrics]** Fix breaking change in web metrics ([#2725](https://github.com/containous/traefik/pull/2725) by [Juliens](https://github.com/Juliens))
|
||||
- **[metrics]** Do not ignore web params when web.metrics.prometheus is set ([#2499](https://github.com/containous/traefik/pull/2499) by [Juliens](https://github.com/Juliens))
|
||||
- **[metrics]** Fix metrics problem on multiple entrypoints ([#2492](https://github.com/containous/traefik/pull/2492) by [Juliens](https://github.com/Juliens))
|
||||
- **[metrics]** Fix data races. ([#2287](https://github.com/containous/traefik/pull/2287) by [tcolgate](https://github.com/tcolgate))
|
||||
- **[metrics]** Flaky test Influxdb. ([#2386](https://github.com/containous/traefik/pull/2386) by [ldez](https://github.com/ldez))
|
||||
- **[middleware,docker,k8s]** Fix custom headers template ([#2621](https://github.com/containous/traefik/pull/2621) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** Don't panic if ResponseWriter does not implement CloseNotify ([#2651](https://github.com/containous/traefik/pull/2651) by [Juliens](https://github.com/Juliens))
|
||||
- **[middleware]** GzipResponse must implement CloseNotifier if ResponseWriter implement it ([#2657](https://github.com/containous/traefik/pull/2657) by [Juliens](https://github.com/Juliens))
|
||||
- **[middleware]** Fix RawPath handling in addPrefix ([#2560](https://github.com/containous/traefik/pull/2560) by [risdenk](https://github.com/risdenk))
|
||||
- **[middleware]** We need to flush the end of the body when retry is streamed ([#2644](https://github.com/containous/traefik/pull/2644) by [Juliens](https://github.com/Juliens))
|
||||
- **[provider]** Fix typo in frontend.headers.customresponseheaders label ([#2356](https://github.com/containous/traefik/pull/2356) by [nmandery](https://github.com/nmandery))
|
||||
- **[provider]** Fix concurrent provider config reloads ([#2276](https://github.com/containous/traefik/pull/2276) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[rancher]** Don't reload configuration when rancher server is down ([#2706](https://github.com/containous/traefik/pull/2706) by [wacken89](https://github.com/wacken89))
|
||||
- **[rules]** Add non regex pathPrefix ([#2592](https://github.com/containous/traefik/pull/2592) by [emilevauge](https://github.com/emilevauge))
|
||||
- **[servicefabric]** Fix backend name for Stateful services. (Service Fabric) ([#2559](https://github.com/containous/traefik/pull/2559) by [ldez](https://github.com/ldez))
|
||||
- **[servicefabric]** Fix isHealthy logic. ([#2577](https://github.com/containous/traefik/pull/2577) by [ldez](https://github.com/ldez))
|
||||
- **[servicefabric]** Service Fabric 'expose' as boolean. ([#2476](https://github.com/containous/traefik/pull/2476) by [ldez](https://github.com/ldez))
|
||||
- **[tls]** Allow deleting dynamically all TLS certificates from an entryPoint ([#2603](https://github.com/containous/traefik/pull/2603) by [nmengin](https://github.com/nmengin))
|
||||
- **[websocket]** Disable websocket compression ([#2727](https://github.com/containous/traefik/pull/2727) by [Juliens](https://github.com/Juliens))
|
||||
- **[websocket]** Add compression and better error handling ([#2702](https://github.com/containous/traefik/pull/2702) by [Juliens](https://github.com/Juliens))
|
||||
- **[websocket]** Use gorilla readMessage and writeMessage instead of just an io.Copy ([#2650](https://github.com/containous/traefik/pull/2650) by [Juliens](https://github.com/Juliens))
|
||||
- **[websocket]** RawPath and Transfer TLSConfig in websocket ([#2077](https://github.com/containous/traefik/pull/2077) by [Juliens](https://github.com/Juliens))
|
||||
- **[zk]** Change Zookeeper default prefix. ([#2580](https://github.com/containous/traefik/pull/2580) by [ldez](https://github.com/ldez))
|
||||
- Fix wrong default entry point and non-existing entry point issue ([#2501](https://github.com/containous/traefik/pull/2501) by [Juliens](https://github.com/Juliens))
|
||||
- Fix goroutine leak in throttler logic. ([#2739](https://github.com/containous/traefik/pull/2739) by [timoreimann](https://github.com/timoreimann))
|
||||
- Fix timeout integration test ([#2679](https://github.com/containous/traefik/pull/2679) by [ldez](https://github.com/ldez))
|
||||
- Fix frontend redirect ([#2544](https://github.com/containous/traefik/pull/2544) by [ldez](https://github.com/ldez))
|
||||
- Close ring buffer used in throttling function. ([#2532](https://github.com/containous/traefik/pull/2532) by [timoreimann](https://github.com/timoreimann))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Improve documentation for Cloudflare API key ([#2558](https://github.com/containous/traefik/pull/2558) by [mmatur](https://github.com/mmatur))
|
||||
- **[acme]** Update Let's Encrypt provider list ([#2347](https://github.com/containous/traefik/pull/2347) by [mmatur](https://github.com/mmatur))
|
||||
- **[cluster]** Add a clustering example with Docker Swarm ([#2589](https://github.com/containous/traefik/pull/2589) by [jmaitrehenry](https://github.com/jmaitrehenry))
|
||||
- **[consul,consulcatalog]** Split Consul and Consul Catalog documentation ([#2654](https://github.com/containous/traefik/pull/2654) by [ldez](https://github.com/ldez))
|
||||
- **[consul]** Improve Consul documentation ([#2485](https://github.com/containous/traefik/pull/2485) by [mmatur](https://github.com/mmatur))
|
||||
- **[docker/swarm]** Typo in docker.endpoint TCP port. ([#2626](https://github.com/containous/traefik/pull/2626) by [redhandpl](https://github.com/redhandpl))
|
||||
- **[docker]** Fix Docker labels documentation render. ([#2505](https://github.com/containous/traefik/pull/2505) by [ldez](https://github.com/ldez))
|
||||
- **[docker]** Add a note on how to add label to a docker compose file ([#2611](https://github.com/containous/traefik/pull/2611) by [jmaitrehenry](https://github.com/jmaitrehenry))
|
||||
- **[etcd]** Fix typo in examples ([#2446](https://github.com/containous/traefik/pull/2446) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- **[k8s]** Add note to Kubernetes RBAC docs about RoleBindings and namespaces ([#2498](https://github.com/containous/traefik/pull/2498) by [jmara](https://github.com/jmara))
|
||||
- **[k8s]** k8s guide: Leave note about assumed DaemonSet usage. ([#2634](https://github.com/containous/traefik/pull/2634) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[k8s]** Apply various contentual and stylish improvements to the k8s docs. ([#2677](https://github.com/containous/traefik/pull/2677) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[k8s]** Document rewrite-target annotation. ([#2676](https://github.com/containous/traefik/pull/2676) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[k8s]** Remove obsolete links in k8s docs ([#2465](https://github.com/containous/traefik/pull/2465) by [marco-jantke](https://github.com/marco-jantke))
|
||||
- **[k8s]** Document filename parameter for Kubernetes. ([#2464](https://github.com/containous/traefik/pull/2464) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[marathon]** Improve Marathon service label documentation. ([#2635](https://github.com/containous/traefik/pull/2635) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[metrics]** Add entrypoint in Prometheus doc and remove web on Influxdb doc ([#2452](https://github.com/containous/traefik/pull/2452) by [Juliens](https://github.com/Juliens))
|
||||
- **[provider,webui]** Fix redirect problem on dashboard + docs/tests on [web] ([#2686](https://github.com/containous/traefik/pull/2686) by [Juliens](https://github.com/Juliens))
|
||||
- **[servicefabric]** Describe 'refreshSecond' configuration. ([#2471](https://github.com/containous/traefik/pull/2471) by [ldez](https://github.com/ldez))
|
||||
- **[tls]** Fix doc dynamic certificates ([#2737](https://github.com/containous/traefik/pull/2737) by [emilevauge](https://github.com/emilevauge))
|
||||
- **[tls]** Add link to crypto/tls godoc. ([#2470](https://github.com/containous/traefik/pull/2470) by [ldez](https://github.com/ldez))
|
||||
- Move rate limit documentation. ([#2588](https://github.com/containous/traefik/pull/2588) by [ldez](https://github.com/ldez))
|
||||
- Grammar ([#2562](https://github.com/containous/traefik/pull/2562) by [geraldcroes](https://github.com/geraldcroes))
|
||||
- Fix some doc links ([#2731](https://github.com/containous/traefik/pull/2731) by [eldondev](https://github.com/eldondev))
|
||||
- Fix broken links and improve ResponseCodeRatio() description ([#2538](https://github.com/containous/traefik/pull/2538) by [mvasin](https://github.com/mvasin))
|
||||
- Fix typo in anonymous usage log message. ([#2711](https://github.com/containous/traefik/pull/2711) by [Yggdrasil](https://github.com/Yggdrasil))
|
||||
- Fix typos in changelog ([#2387](https://github.com/containous/traefik/pull/2387) by [ferhatelmas](https://github.com/ferhatelmas))
|
||||
- Add mmatur to maintainers ([#2303](https://github.com/containous/traefik/pull/2303) by [emilevauge](https://github.com/emilevauge))
|
||||
- Add a note about redirection rule to precise how regex/replacement work. ([#2243](https://github.com/containous/traefik/pull/2243) by [nmengin](https://github.com/nmengin))
|
||||
- Add docker things for documentation ([#2020](https://github.com/containous/traefik/pull/2020) by [tcoupin](https://github.com/tcoupin))
|
||||
- Prepare release v1.5.0-rc5 ([#2707](https://github.com/containous/traefik/pull/2707) by [mmatur](https://github.com/mmatur))
|
||||
- Prepare release v1.5.0-rc4 ([#2656](https://github.com/containous/traefik/pull/2656) by [Juliens](https://github.com/Juliens))
|
||||
- Prepare release v1.5.0-rc3 ([#2599](https://github.com/containous/traefik/pull/2599) by [ldez](https://github.com/ldez))
|
||||
- Prepare release v1.5.0-rc2 ([#2533](https://github.com/containous/traefik/pull/2533) by [ldez](https://github.com/ldez))
|
||||
- Prepare release v1.5.0-rc1 ([#2480](https://github.com/containous/traefik/pull/2480) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Misc:**
|
||||
- **[acme]** dumpcerts.sh: Fix call to "base64" for Alpine ([#2344](https://github.com/containous/traefik/pull/2344) by [nknapp](https://github.com/nknapp))
|
||||
- **[acme]** dumpcerts.sh: fixed sed, extracted domain keys ([#2161](https://github.com/containous/traefik/pull/2161) by [sjawhar](https://github.com/sjawhar))
|
||||
- **[etcd,kv,tls]** Add tests for TLS dynamic configuration in ETCD3 ([#2606](https://github.com/containous/traefik/pull/2606) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- Upgrade libkermit/compose version ([#2074](https://github.com/containous/traefik/pull/2074) by [nmengin](https://github.com/nmengin))
|
||||
- Merge v1.4.6 into v1.5 ([#2642](https://github.com/containous/traefik/pull/2642) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.5 into v1.5 ([#2530](https://github.com/containous/traefik/pull/2530) by [mmatur](https://github.com/mmatur))
|
||||
- Merge current v1.4 into master ([#2479](https://github.com/containous/traefik/pull/2479) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.3 into master ([#2415](https://github.com/containous/traefik/pull/2415) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.4 into master ([#2457](https://github.com/containous/traefik/pull/2457) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.3 into master ([#2406](https://github.com/containous/traefik/pull/2406) by [ldez](https://github.com/ldez))
|
||||
- Revert "Merge v1.4.2 into master" ([#2414](https://github.com/containous/traefik/pull/2414) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.2 into master ([#2358](https://github.com/containous/traefik/pull/2358) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.1 into master ([#2318](https://github.com/containous/traefik/pull/2318) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.0 ([#2271](https://github.com/containous/traefik/pull/2271) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.0-rc5 into master ([#2242](https://github.com/containous/traefik/pull/2242) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.0-rc4 into master ([#2202](https://github.com/containous/traefik/pull/2202) by [ldez](https://github.com/ldez))
|
||||
- Merge current v1.4 into master ([#2469](https://github.com/containous/traefik/pull/2469) by [ldez](https://github.com/ldez))
|
||||
- Merge current v1.4 ([#2154](https://github.com/containous/traefik/pull/2154) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.0-rc3 into master ([#2140](https://github.com/containous/traefik/pull/2140) by [ldez](https://github.com/ldez))
|
||||
- Merge v1.4.0-rc2 into master ([#2092](https://github.com/containous/traefik/pull/2092) by [ldez](https://github.com/ldez))
|
||||
- Merge current 1.4 ([#2064](https://github.com/containous/traefik/pull/2064) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.5.0-rc5](https://github.com/containous/traefik/tree/v1.5.0-rc5) (2018-01-15)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc4...v1.5.0-rc5)
|
||||
|
||||
**Enhancements:**
|
||||
- **[acme]** Add Let's Encrypt HTTP Challenge ([#2701](https://github.com/containous/traefik/pull/2701) by [Juliens](https://github.com/Juliens))
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,logs]** Modify DEBUG messages to get ACME certificates ([#2685](https://github.com/containous/traefik/pull/2685) by [nmengin](https://github.com/nmengin))
|
||||
- **[authentication,middleware]** Fix concurrent map writes on digest auth ([#2695](https://github.com/containous/traefik/pull/2695) by [mmatur](https://github.com/mmatur))
|
||||
- **[docker]** Typo in Docker template. ([#2692](https://github.com/containous/traefik/pull/2692) by [ldez](https://github.com/ldez))
|
||||
- **[docker]** Return errors from Docker client.Events ([#2689](https://github.com/containous/traefik/pull/2689) by [BlakeMesdag](https://github.com/BlakeMesdag))
|
||||
- **[kv]** List entries parsing. ([#2669](https://github.com/containous/traefik/pull/2669) by [ldez](https://github.com/ldez))
|
||||
- **[metrics]** Fix data races. ([#2287](https://github.com/containous/traefik/pull/2287) by [tcolgate](https://github.com/tcolgate))
|
||||
- **[middleware]** GzipResponse must implement CloseNotifier if ResponseWriter implement it ([#2657](https://github.com/containous/traefik/pull/2657) by [Juliens](https://github.com/Juliens))
|
||||
- **[websocket]** Add compression and better error handling ([#2702](https://github.com/containous/traefik/pull/2702) by [Juliens](https://github.com/Juliens))
|
||||
- Fix: timeout integration test ([#2679](https://github.com/containous/traefik/pull/2679) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[cluster]** Add a clustering example with Docker Swarm ([#2589](https://github.com/containous/traefik/pull/2589) by [jmaitrehenry](https://github.com/jmaitrehenry))
|
||||
- **[k8s]** Apply various contentual and stylish improvements to the k8s docs. ([#2677](https://github.com/containous/traefik/pull/2677) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[k8s]** Document rewrite-target annotation. ([#2676](https://github.com/containous/traefik/pull/2676) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[provider,webui]** Fix redirect problem on dashboard + docs/tests on [web] ([#2686](https://github.com/containous/traefik/pull/2686) by [Juliens](https://github.com/Juliens))
|
||||
|
||||
## [v1.5.0-rc4](https://github.com/containous/traefik/tree/v1.5.0-rc4) (2018-01-04)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc3...v1.5.0-rc4)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[consulcatalog]** Use prefix for sticky and stickiness tags. ([#2624](https://github.com/containous/traefik/pull/2624) by [ldez](https://github.com/ldez))
|
||||
- **[file,tls]** Send empty configuration from file provider ([#2609](https://github.com/containous/traefik/pull/2609) by [nmengin](https://github.com/nmengin))
|
||||
- **[middleware,docker,k8s]** Fix custom headers template ([#2621](https://github.com/containous/traefik/pull/2621) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** Don't panic if ResponseWriter does not implement CloseNotify ([#2651](https://github.com/containous/traefik/pull/2651) by [Juliens](https://github.com/Juliens))
|
||||
- **[middleware]** We need to flush the end of the body when retry is streamed ([#2644](https://github.com/containous/traefik/pull/2644) by [Juliens](https://github.com/Juliens))
|
||||
- **[tls]** Allow deleting dynamically all TLS certificates from an entryPoint ([#2603](https://github.com/containous/traefik/pull/2603) by [nmengin](https://github.com/nmengin))
|
||||
- **[websocket]** Use gorilla readMessage and writeMessage instead of just an io.Copy ([#2650](https://github.com/containous/traefik/pull/2650) by [Juliens](https://github.com/Juliens))
|
||||
|
||||
**Documentation:**
|
||||
- **[consul,consulcatalog]** Split Consul and Consul Catalog documentation ([#2654](https://github.com/containous/traefik/pull/2654) by [ldez](https://github.com/ldez))
|
||||
- **[docker/swarm]** Typo in docker.endpoint TCP port. ([#2626](https://github.com/containous/traefik/pull/2626) by [redhandpl](https://github.com/redhandpl))
|
||||
- **[docker]** Add a note on how to add label to a docker compose file ([#2611](https://github.com/containous/traefik/pull/2611) by [jmaitrehenry](https://github.com/jmaitrehenry))
|
||||
- **[k8s]** k8s guide: Leave note about assumed DaemonSet usage. ([#2634](https://github.com/containous/traefik/pull/2634) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[marathon]** Improve Marathon service label documentation. ([#2635](https://github.com/containous/traefik/pull/2635) by [timoreimann](https://github.com/timoreimann))
|
||||
|
||||
**Misc:**
|
||||
- **[etcd,kv,tls]** Add tests for TLS dynamic configuration in ETCD3 ([#2606](https://github.com/containous/traefik/pull/2606) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- Merge v1.4.6 into v1.5 ([#2642](https://github.com/containous/traefik/pull/2642) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.4.6](https://github.com/containous/traefik/tree/v1.4.6) (2018-01-02)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.4.5...v1.4.6)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[docker]** Normalize serviceName added to the service backend names ([#2631](https://github.com/containous/traefik/pull/2631) by [mmatur](https://github.com/mmatur))
|
||||
- **[websocket]** Use gorilla readMessage and writeMessage instead of just an io.Copy ([#2640](https://github.com/containous/traefik/pull/2640) by [Juliens](https://github.com/Juliens))
|
||||
- Fix bug report command ([#2638](https://github.com/containous/traefik/pull/2638) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.5.0-rc3](https://github.com/containous/traefik/tree/v1.5.0-rc3) (2017-12-20)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc2...v1.5.0-rc3)
|
||||
|
||||
**Enhancements:**
|
||||
- **[docker,k8s,rancher]** Support regex redirect by frontend ([#2570](https://github.com/containous/traefik/pull/2570) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,docker]** Modify ACME configuration migration into KV store ([#2598](https://github.com/containous/traefik/pull/2598) by [nmengin](https://github.com/nmengin))
|
||||
- **[consulcatalog]** Reload configuration when port change for one service ([#2574](https://github.com/containous/traefik/pull/2574) by [mmatur](https://github.com/mmatur))
|
||||
- **[consulcatalog]** Fix bad Træfik update on Consul Catalog ([#2573](https://github.com/containous/traefik/pull/2573) by [mmatur](https://github.com/mmatur))
|
||||
- **[k8s]** Add missing entrypoints template. ([#2594](https://github.com/containous/traefik/pull/2594) by [ldez](https://github.com/ldez))
|
||||
- **[kv]** Fix stickiness bug due to template syntax error ([#2591](https://github.com/containous/traefik/pull/2591) by [dahefanteng](https://github.com/dahefanteng))
|
||||
- **[marathon]** Update go-marathon ([#2585](https://github.com/containous/traefik/pull/2585) by [timoreimann](https://github.com/timoreimann))
|
||||
- **[mesos]** Mesos: Use slave.PID.Host as task SlaveIP. ([#2590](https://github.com/containous/traefik/pull/2590) by [nemosupremo](https://github.com/nemosupremo))
|
||||
- **[middleware]** Fix RawPath handling in addPrefix ([#2560](https://github.com/containous/traefik/pull/2560) by [risdenk](https://github.com/risdenk))
|
||||
- **[rules]** Add non regex pathPrefix ([#2592](https://github.com/containous/traefik/pull/2592) by [emilevauge](https://github.com/emilevauge))
|
||||
- **[servicefabric]** Fix backend name for Stateful services. (Service Fabric) ([#2559](https://github.com/containous/traefik/pull/2559) by [ldez](https://github.com/ldez))
|
||||
- **[servicefabric]** Fix isHealthy logic. ([#2577](https://github.com/containous/traefik/pull/2577) by [ldez](https://github.com/ldez))
|
||||
- **[zk]** Change Zookeeper default prefix. ([#2580](https://github.com/containous/traefik/pull/2580) by [ldez](https://github.com/ldez))
|
||||
- Fix frontend redirect ([#2544](https://github.com/containous/traefik/pull/2544) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[acme]** Improve documentation for Cloudflare API key ([#2558](https://github.com/containous/traefik/pull/2558) by [mmatur](https://github.com/mmatur))
|
||||
- Move rate limit documentation. ([#2588](https://github.com/containous/traefik/pull/2588) by [ldez](https://github.com/ldez))
|
||||
- Grammar ([#2562](https://github.com/containous/traefik/pull/2562) by [geraldcroes](https://github.com/geraldcroes))
|
||||
- Fix broken links and improve ResponseCodeRatio() description ([#2538](https://github.com/containous/traefik/pull/2538) by [mvasin](https://github.com/mvasin))
|
||||
|
||||
## [v1.5.0-rc2](https://github.com/containous/traefik/tree/v1.5.0-rc2) (2017-12-06)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.5.0-rc2)
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
## Building
|
||||
|
||||
You need either [Docker](https://github.com/docker/docker) and `make` (Method 1), or `go` (Method 2) in order to build Traefik. For changes to its dependencies, the `glide` dependency management tool and `glide-vc` plugin are required.
|
||||
You need either [Docker](https://github.com/docker/docker) and `make` (Method 1), or `go` (Method 2) in order to build Traefik.
|
||||
For changes to its dependencies, the `dep` dependency management tool is required.
|
||||
|
||||
### Method 1: Using `Docker` and `Makefile`
|
||||
|
||||
@@ -14,7 +15,7 @@ docker build -t "traefik-dev:no-more-godep-ever" -f build.Dockerfile .
|
||||
Sending build context to Docker daemon 295.3 MB
|
||||
Step 0 : FROM golang:1.9-alpine
|
||||
---> 8c6473912976
|
||||
Step 1 : RUN go get github.com/Masterminds/glide
|
||||
Step 1 : RUN go get github.com/golang/dep/cmd/dep
|
||||
[...]
|
||||
docker run --rm -v "/var/run/docker.sock:/var/run/docker.sock" -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -v "/home/user/go/src/github.com/containous/traefik/"dist":/go/src/github.com/containous/traefik/"dist"" "traefik-dev:no-more-godep-ever" ./script/make.sh generate binary
|
||||
---> Making bundle: generate (in .)
|
||||
@@ -63,7 +64,7 @@ Once your environment is set up and the Træfik repository cloned you can build
|
||||
cd ~/go/src/github.com/containous/traefik
|
||||
|
||||
# Get go-bindata. Please note, the ellipses are required
|
||||
go get github.com/jteeuwen/go-bindata/...
|
||||
go get github.com/containous/go-bindata/...
|
||||
|
||||
# Start build
|
||||
|
||||
@@ -82,21 +83,22 @@ You will find the Træfik executable in the `~/go/src/github.com/containous/trae
|
||||
|
||||
If you happen to update the provider templates (in `/templates`), you need to run `go generate` to update the `autogen` package.
|
||||
|
||||
### Setting up `glide` and `glide-vc` for dependency management
|
||||
### Setting up dependency management
|
||||
|
||||
- Glide is not required for building; however, it is necessary to modify dependencies (i.e., add, update, or remove third-party packages)
|
||||
- Glide can be installed either via homebrew: `$ brew install glide` or via the official glide script: `$ curl https://glide.sh/get | sh`
|
||||
- The glide plugin `glide-vc` must be installed from source: `go get github.com/sgotti/glide-vc`
|
||||
[dep](https://github.com/golang/dep) is not required for building; however, it is necessary to modify dependencies (i.e., add, update, or remove third-party packages)
|
||||
|
||||
If you want to add a dependency, use `$ glide get` to have glide put it into the vendor folder and update the glide manifest/lock files (`glide.yaml` and `glide.lock`, respectively). A following `glide-vc` run should be triggered to trim down the size of the vendor folder. The final result must be committed into VCS.
|
||||
You need to use [dep](https://github.com/golang/dep) >= O.4.1.
|
||||
|
||||
Care must be taken to choose the right arguments to `glide` when dealing with dependencies, or otherwise risk ending up with a broken build. For that reason, the helper script `script/glide.sh` encapsulates the gory details and conveniently calls `glide-vc` as well. Call it without parameters for basic usage instructions.
|
||||
If you want to add a dependency, use `dep ensure -add` to have [dep](https://github.com/golang/dep) put it into the vendor folder and update the dep manifest/lock files (`Gopkg.toml` and `Gopkg.lock`, respectively).
|
||||
|
||||
Here's a full example using glide to add a new dependency:
|
||||
A following `make dep-prune` run should be triggered to trim down the size of the vendor folder.
|
||||
The final result must be committed into VCS.
|
||||
|
||||
Here's a full example using dep to add a new dependency:
|
||||
|
||||
```bash
|
||||
# install the new main dependency github.com/foo/bar and minimize vendor size
|
||||
$ ./script/glide.sh get github.com/foo/bar
|
||||
$ dep ensure -add github.com/foo/bar
|
||||
# generate (Only required to integrate other components such as web dashboard)
|
||||
$ go generate
|
||||
# Standard go build
|
||||
@@ -127,6 +129,7 @@ Test success
|
||||
```
|
||||
|
||||
For development purposes, you can specify which tests to run by using:
|
||||
|
||||
```bash
|
||||
# Run every tests in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite" make test-integration
|
||||
@@ -146,6 +149,7 @@ More: https://labix.org/gocheck
|
||||
#### Method 2: `go`
|
||||
|
||||
Unit tests can be run from the cloned directory by `$ go test ./...` which should return `ok` similar to:
|
||||
|
||||
```
|
||||
ok _/home/user/go/src/github/containous/traefik 0.004s
|
||||
```
|
||||
|
||||
1395
Gopkg.lock
generated
Normal file
1395
Gopkg.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
197
Gopkg.toml
Normal file
197
Gopkg.toml
Normal file
@@ -0,0 +1,197 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = ["github.com/sirupsen/logrus"]
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/ArthurHlt/go-eureka-client"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/BurntSushi/toml"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/BurntSushi/ty"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/NYTimes/gziphandler"
|
||||
|
||||
[[constraint]]
|
||||
branch = "containous-fork"
|
||||
name = "github.com/abbot/go-http-auth"
|
||||
source = "github.com/containous/go-http-auth"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/armon/go-proxyproto"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
version = "1.6.18"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/cenk/backoff"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/containous/flaeg"
|
||||
version = "1.0.1"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/containous/mux"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/containous/staert"
|
||||
version = "2.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/containous/traefik-extra-service-fabric"
|
||||
version = "1.0.5"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/coreos/go-systemd"
|
||||
version = "14.0.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/docker/leadership"
|
||||
source = "github.com/containous/leadership"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/libkv"
|
||||
source = "github.com/abronan/libkv"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/eapache/channels"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/elazarl/go-bindata-assetfs"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-check/check"
|
||||
source = "github.com/containous/check"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-kit/kit"
|
||||
version = "0.3.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/influxdata/influxdb"
|
||||
version = "1.3.7"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/jjcollinge/servicefabric"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-shellwords"
|
||||
version = "1.0.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mesosphere/mesos-dns"
|
||||
source = "https://github.com/containous/mesos-dns.git"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/copystructure"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/hashstructure"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/rancher/go-rancher-metadata"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/ryanuber/go-glob"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/satori/go.uuid"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/stvp/go-udp-testing"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/vdemeester/shakers"
|
||||
version = "0.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "containous-fork"
|
||||
name = "github.com/vulcand/oxy"
|
||||
source = "https://github.com/containous/oxy.git"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/xenolf/lego"
|
||||
version = "0.4.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "google.golang.org/grpc"
|
||||
version = "1.5.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/fsnotify.v1"
|
||||
version = "1.4.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/client-go"
|
||||
version = "2.0.0"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/Nvveen/Gotty"
|
||||
revision = "6018b68f96b839edfbe3fb48668853f5dbad88a3"
|
||||
source = "github.com/ijc25/Gotty"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
revision = "a69d9f6de432e2c6b296a947d8a5ee88f68522cf"
|
||||
|
||||
[[override]]
|
||||
# always keep this override
|
||||
name = "github.com/mailgun/timetools"
|
||||
revision = "7e6055773c5137efbeb3bd2410d705fe10ab6bfd"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/vulcand/predicate"
|
||||
revision = "19b9dde14240d94c804ae5736ad0e1de10bf8fe6"
|
||||
|
||||
[[override]]
|
||||
# remove override on master
|
||||
name = "github.com/coreos/bbolt"
|
||||
revision = "32c383e75ce054674c53b5a07e55de85332aee14"
|
||||
|
||||
[prune]
|
||||
non-go = true
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2017 Containous SAS
|
||||
Copyright (c) 2016-2018 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
9
Makefile
9
Makefile
@@ -74,7 +74,7 @@ test-integration: build ## run the integration tests
|
||||
TEST_HOST=1 ./script/make.sh test-integration
|
||||
|
||||
validate: build ## validate gofmt, golint and go vet
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-glide validate-gofmt validate-govet validate-golint validate-misspell validate-vendor validate-autogen
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-gofmt validate-govet validate-golint validate-misspell validate-vendor validate-autogen
|
||||
|
||||
build: dist
|
||||
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||
@@ -127,5 +127,12 @@ fmt:
|
||||
pull-images:
|
||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
|
||||
|
||||
dep-ensure:
|
||||
dep ensure -v
|
||||
./script/prune-dep.sh
|
||||
|
||||
dep-prune:
|
||||
./script/prune-dep.sh
|
||||
|
||||
help: ## this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
[](https://twitter.com/intent/follow?screen_name=traefikproxy)
|
||||
|
||||
|
||||
Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
Træfik (pronounced like _traffic_) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
It supports several backends ([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 a lot more) to manage its configuration automatically and dynamically.
|
||||
|
||||
---
|
||||
@@ -43,7 +43,7 @@ If you want your users to access some of your microservices from the Internet, y
|
||||
- path `domain.com/web` will point the microservice `web` in your private network
|
||||
- domain `backoffice.domain.com` will point the microservices `backoffice` in your private network, load-balancing between your multiple instances
|
||||
|
||||
But a microservices architecture is dynamic... Services are added, removed, killed or upgraded often, eventually several times a day.
|
||||
Microservices are often deployed in dynamic environments where services are added, removed, killed, upgraded or scaled many times a day.
|
||||
|
||||
Traditional reverse-proxies are not natively dynamic. You can't change their configuration and hot-reload easily.
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ type Account struct {
|
||||
PrivateKey []byte
|
||||
DomainsCertificate DomainsCertificates
|
||||
ChallengeCerts map[string]*ChallengeCert
|
||||
HTTPChallenge map[string]map[string][]byte
|
||||
}
|
||||
|
||||
// ChallengeCert stores a challenge certificate
|
||||
@@ -221,6 +222,24 @@ func (dc *DomainsCertificates) exists(domainToFind Domain) (*DomainsCertificate,
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (dc *DomainsCertificates) toDomainsMap() map[string]*tls.Certificate {
|
||||
domainsCertificatesMap := make(map[string]*tls.Certificate)
|
||||
for _, domainCertificate := range dc.Certs {
|
||||
certKey := domainCertificate.Domains.Main
|
||||
if domainCertificate.Domains.SANs != nil {
|
||||
sort.Strings(domainCertificate.Domains.SANs)
|
||||
for _, dnsName := range domainCertificate.Domains.SANs {
|
||||
if dnsName != domainCertificate.Domains.Main {
|
||||
certKey += fmt.Sprintf(",%s", dnsName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
domainsCertificatesMap[certKey] = domainCertificate.tlsCert
|
||||
}
|
||||
return domainsCertificatesMap
|
||||
}
|
||||
|
||||
// DomainsCertificate contains a certificate for multiple domains
|
||||
type DomainsCertificate struct {
|
||||
Domains Domain
|
||||
|
||||
364
acme/acme.go
364
acme/acme.go
@@ -7,6 +7,8 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
fmtlog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -14,6 +16,8 @@ import (
|
||||
|
||||
"github.com/BurntSushi/ty/fun"
|
||||
"github.com/cenk/backoff"
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/mux"
|
||||
"github.com/containous/staert"
|
||||
"github.com/containous/traefik/cluster"
|
||||
"github.com/containous/traefik/log"
|
||||
@@ -33,25 +37,39 @@ var (
|
||||
|
||||
// ACME allows to connect to lets encrypt and retrieve certs
|
||||
type ACME struct {
|
||||
Email string `description:"Email address used for registration"`
|
||||
Domains []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. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."`
|
||||
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."`
|
||||
DNSProvider string `description:"Use a DNS based challenge provider rather than HTTPS."`
|
||||
DelayDontCheckDNS int `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."`
|
||||
ACMELogging bool `description:"Enable debug logging of ACME actions."`
|
||||
client *acme.Client
|
||||
defaultCertificate *tls.Certificate
|
||||
store cluster.Store
|
||||
challengeProvider *challengeProvider
|
||||
checkOnDemandDomain func(domain string) bool
|
||||
jobs *channels.InfiniteChannel
|
||||
TLSConfig *tls.Config `description:"TLS config in case wildcard certs are used"`
|
||||
dynamicCerts *safe.Safe
|
||||
Email string `description:"Email address used for registration"`
|
||||
Domains []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
|
||||
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."`
|
||||
DNSChallenge *DNSChallenge `description:"Activate DNS-01 Challenge"`
|
||||
HTTPChallenge *HTTPChallenge `description:"Activate HTTP-01 Challenge"`
|
||||
DNSProvider string `description:"Use a DNS-01 acme challenge rather than TLS-SNI-01 challenge."` // deprecated
|
||||
DelayDontCheckDNS flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // deprecated
|
||||
ACMELogging bool `description:"Enable debug logging of ACME actions."`
|
||||
client *acme.Client
|
||||
defaultCertificate *tls.Certificate
|
||||
store cluster.Store
|
||||
challengeTLSProvider *challengeTLSProvider
|
||||
challengeHTTPProvider *challengeHTTPProvider
|
||||
checkOnDemandDomain func(domain string) bool
|
||||
jobs *channels.InfiniteChannel
|
||||
TLSConfig *tls.Config `description:"TLS config in case wildcard certs are used"`
|
||||
dynamicCerts *safe.Safe
|
||||
}
|
||||
|
||||
// DNSChallenge contains DNS challenge Configuration
|
||||
type DNSChallenge struct {
|
||||
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS."`
|
||||
DelayBeforeCheck flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."`
|
||||
}
|
||||
|
||||
// HTTPChallenge contains HTTP challenge Configuration
|
||||
type HTTPChallenge struct {
|
||||
EntryPoint string `description:"HTTP challenge EntryPoint"`
|
||||
}
|
||||
|
||||
//Domains parse []Domain
|
||||
@@ -96,6 +114,20 @@ type Domain 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,
|
||||
},
|
||||
}
|
||||
|
||||
if a.ACMELogging {
|
||||
acme.Logger = fmtlog.New(os.Stderr, "legolog: ", fmtlog.LstdFlags)
|
||||
} else {
|
||||
@@ -107,15 +139,39 @@ func (a *ACME) init() error {
|
||||
return err
|
||||
}
|
||||
a.defaultCertificate = cert
|
||||
// TODO: to remove in the futurs
|
||||
if len(a.StorageFile) > 0 && len(a.Storage) == 0 {
|
||||
log.Warn("ACME.StorageFile is deprecated, use ACME.Storage instead")
|
||||
a.Storage = a.StorageFile
|
||||
}
|
||||
|
||||
a.jobs = channels.NewInfiniteChannel()
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRoutes add routes on internal router
|
||||
func (a *ACME) AddRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).
|
||||
Path(acme.HTTP01ChallengePath("{token}")).
|
||||
Handler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if a.challengeHTTPProvider == nil {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(req)
|
||||
if token, ok := vars["token"]; ok {
|
||||
domain, _, err := net.SplitHostPort(req.Host)
|
||||
if err != nil {
|
||||
log.Debugf("Unable to split host and port: %v. Fallback to request host.", err)
|
||||
domain = req.Host
|
||||
}
|
||||
tokenValue := a.challengeHTTPProvider.getTokenValue(token, domain)
|
||||
if len(tokenValue) > 0 {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write(tokenValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
}
|
||||
|
||||
// CreateClusterConfig creates a tls.config using ACME configuration in cluster mode
|
||||
func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tls.Config, certs *safe.Safe, checkOnDemandDomain func(domain string) bool) error {
|
||||
err := a.init()
|
||||
@@ -155,7 +211,7 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl
|
||||
}
|
||||
|
||||
a.store = datastore
|
||||
a.challengeProvider = &challengeProvider{store: a.store}
|
||||
a.challengeTLSProvider = &challengeTLSProvider{store: a.store}
|
||||
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
leadership.Pool.AddGoCtx(func(ctx context.Context) {
|
||||
@@ -171,74 +227,75 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl
|
||||
}
|
||||
})
|
||||
|
||||
leadership.AddListener(func(elected bool) error {
|
||||
if elected {
|
||||
_, err := a.store.Load()
|
||||
leadership.AddListener(a.leadershipListener)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ACME) leadershipListener(elected bool) error {
|
||||
if elected {
|
||||
_, err := a.store.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transaction, object, err := a.store.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account := object.(*Account)
|
||||
account.Init()
|
||||
var needRegister bool
|
||||
if account == nil || len(account.Email) == 0 {
|
||||
account, err = NewAccount(a.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transaction, object, err := a.store.Begin()
|
||||
needRegister = true
|
||||
}
|
||||
a.client, err = a.buildACMEClient(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if needRegister {
|
||||
// New users will need to register; be sure to save it
|
||||
log.Debug("Register...")
|
||||
reg, err := a.client.Register()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account := object.(*Account)
|
||||
account.Init()
|
||||
var needRegister bool
|
||||
if account == nil || len(account.Email) == 0 {
|
||||
account, err = NewAccount(a.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needRegister = true
|
||||
}
|
||||
account.Registration = reg
|
||||
}
|
||||
// The client has a URL to the current Let's Encrypt Subscriber
|
||||
// Agreement. The user will need to agree to it.
|
||||
log.Debug("AgreeToTOS...")
|
||||
err = a.client.AgreeToTOS()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
// Let's Encrypt Subscriber Agreement renew ?
|
||||
reg, err := a.client.QueryRegistration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.client, err = a.buildACMEClient(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if needRegister {
|
||||
// New users will need to register; be sure to save it
|
||||
log.Debug("Register...")
|
||||
reg, err := a.client.Register()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account.Registration = reg
|
||||
}
|
||||
// The client has a URL to the current Let's Encrypt Subscriber
|
||||
// Agreement. The user will need to agree to it.
|
||||
log.Debug("AgreeToTOS...")
|
||||
account.Registration = reg
|
||||
err = a.client.AgreeToTOS()
|
||||
if err != nil {
|
||||
// Let's Encrypt Subscriber Agreement renew ?
|
||||
reg, err := a.client.QueryRegistration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account.Registration = reg
|
||||
err = a.client.AgreeToTOS()
|
||||
if err != nil {
|
||||
log.Errorf("Error sending ACME agreement to TOS: %+v: %s", account, err.Error())
|
||||
}
|
||||
log.Errorf("Error sending ACME agreement to TOS: %+v: %s", account, err.Error())
|
||||
}
|
||||
err = transaction.Commit(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.retrieveCertificates()
|
||||
a.renewCertificates()
|
||||
a.runJobs()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
err = transaction.Commit(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.retrieveCertificates()
|
||||
a.renewCertificates()
|
||||
a.runJobs()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateLocalConfig creates a tls.config using local ACME configuration
|
||||
func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, certs *safe.Safe, checkOnDemandDomain func(domain string) bool) error {
|
||||
defer a.runJobs()
|
||||
err := a.init()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -253,7 +310,7 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, certs *safe.Safe, checkO
|
||||
a.TLSConfig = tlsConfig
|
||||
localStore := NewLocalStore(a.Storage)
|
||||
a.store = localStore
|
||||
a.challengeProvider = &challengeProvider{store: a.store}
|
||||
a.challengeTLSProvider = &challengeTLSProvider{store: a.store}
|
||||
|
||||
var needRegister bool
|
||||
var account *Account
|
||||
@@ -277,7 +334,9 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, certs *safe.Safe, checkO
|
||||
|
||||
a.client, err = a.buildACMEClient(account)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Errorf(`Failed to build ACME client: %s
|
||||
Let's Encrypt functionality will be limited until traefik is restarted.`, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if needRegister {
|
||||
@@ -318,7 +377,6 @@ func (a *ACME) CreateLocalConfig(tlsConfig *tls.Config, certs *safe.Safe, checkO
|
||||
|
||||
a.retrieveCertificates()
|
||||
a.renewCertificates()
|
||||
a.runJobs()
|
||||
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
safe.Go(func() {
|
||||
@@ -333,11 +391,11 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
|
||||
domain := types.CanonicalDomain(clientHello.ServerName)
|
||||
account := a.store.Get().(*Account)
|
||||
|
||||
if providedCertificate := a.getProvidedCertificate([]string{domain}); providedCertificate != nil {
|
||||
if providedCertificate := a.getProvidedCertificate(domain); providedCertificate != nil {
|
||||
return providedCertificate, nil
|
||||
}
|
||||
|
||||
if challengeCert, ok := a.challengeProvider.getCertificate(domain); ok {
|
||||
if challengeCert, ok := a.challengeTLSProvider.getCertificate(domain); ok {
|
||||
log.Debugf("ACME got challenge %s", domain)
|
||||
return challengeCert, nil
|
||||
}
|
||||
@@ -351,7 +409,7 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
|
||||
}
|
||||
return a.loadCertificateOnDemand(clientHello)
|
||||
}
|
||||
log.Debugf("ACME got nothing %s", domain)
|
||||
log.Debugf("No certificate found or generated for %s", domain)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -472,16 +530,16 @@ func (a *ACME) storeRenewedCertificate(account *Account, certificateResource *Do
|
||||
return nil
|
||||
}
|
||||
|
||||
func dnsOverrideDelay(delay int) error {
|
||||
func dnsOverrideDelay(delay flaeg.Duration) error {
|
||||
var err error
|
||||
if delay > 0 {
|
||||
log.Debugf("Delaying %d seconds rather than validating DNS propagation", delay)
|
||||
log.Debugf("Delaying %d rather than validating DNS propagation", delay)
|
||||
acme.PreCheckDNS = func(_, _ string) (bool, error) {
|
||||
time.Sleep(time.Duration(delay) * time.Second)
|
||||
time.Sleep(time.Duration(delay))
|
||||
return true, nil
|
||||
}
|
||||
} else if delay < 0 {
|
||||
err = fmt.Errorf("invalid negative DelayDontCheckDNS: %d", delay)
|
||||
err = fmt.Errorf("invalid negative DelayBeforeCheck: %d", delay)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -497,25 +555,29 @@ func (a *ACME) buildACMEClient(account *Account) (*acme.Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(a.DNSProvider) > 0 {
|
||||
log.Debugf("Using DNS Challenge provider: %s", a.DNSProvider)
|
||||
if a.DNSChallenge != nil && len(a.DNSChallenge.Provider) > 0 {
|
||||
log.Debugf("Using DNS Challenge provider: %s", a.DNSChallenge.Provider)
|
||||
|
||||
err = dnsOverrideDelay(a.DelayDontCheckDNS)
|
||||
err = dnsOverrideDelay(a.DNSChallenge.DelayBeforeCheck)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var provider acme.ChallengeProvider
|
||||
provider, err = dns.NewDNSChallengeProviderByName(a.DNSProvider)
|
||||
provider, err = dns.NewDNSChallengeProviderByName(a.DNSChallenge.Provider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.TLSSNI01})
|
||||
err = client.SetChallengeProvider(acme.DNS01, provider)
|
||||
} else if a.HTTPChallenge != nil && len(a.HTTPChallenge.EntryPoint) > 0 {
|
||||
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
|
||||
a.challengeHTTPProvider = &challengeHTTPProvider{store: a.store}
|
||||
err = client.SetChallengeProvider(acme.HTTP01, a.challengeHTTPProvider)
|
||||
} else {
|
||||
client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.DNS01})
|
||||
err = client.SetChallengeProvider(acme.TLSSNI01, a.challengeProvider)
|
||||
err = client.SetChallengeProvider(acme.TLSSNI01, a.challengeTLSProvider)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -563,11 +625,6 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
||||
|
||||
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
||||
|
||||
// Check provided certificates
|
||||
if a.getProvidedCertificate(domains) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
operation := func() error {
|
||||
if a.client == nil {
|
||||
return errors.New("ACME client still not built")
|
||||
@@ -585,32 +642,34 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
||||
return
|
||||
}
|
||||
account := a.store.Get().(*Account)
|
||||
var domain Domain
|
||||
if len(domains) > 1 {
|
||||
domain = Domain{Main: domains[0], SANs: domains[1:]}
|
||||
} else {
|
||||
domain = Domain{Main: domains[0]}
|
||||
}
|
||||
if _, exists := account.DomainsCertificate.exists(domain); exists {
|
||||
// domain already exists
|
||||
|
||||
// Check provided certificates
|
||||
uncheckedDomains := a.getUncheckedDomains(domains, account)
|
||||
if len(uncheckedDomains) == 0 {
|
||||
return
|
||||
}
|
||||
certificate, err := a.getDomainsCertificates(domains)
|
||||
certificate, err := a.getDomainsCertificates(uncheckedDomains)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting ACME certificates %+v : %v", domains, err)
|
||||
log.Errorf("Error getting ACME certificates %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
log.Debugf("Got certificate for domains %+v", domains)
|
||||
log.Debugf("Got certificate for domains %+v", uncheckedDomains)
|
||||
transaction, object, err := a.store.Begin()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error creating transaction %+v : %v", domains, err)
|
||||
log.Errorf("Error creating transaction %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
var domain Domain
|
||||
if len(uncheckedDomains) > 1 {
|
||||
domain = Domain{Main: uncheckedDomains[0], SANs: uncheckedDomains[1:]}
|
||||
} else {
|
||||
domain = Domain{Main: uncheckedDomains[0]}
|
||||
}
|
||||
account = object.(*Account)
|
||||
_, err = account.DomainsCertificate.addCertificateForDomains(certificate, domain)
|
||||
if err != nil {
|
||||
log.Errorf("Error adding ACME certificates %+v : %v", domains, err)
|
||||
log.Errorf("Error adding ACME certificates %+v : %v", uncheckedDomains, err)
|
||||
return
|
||||
}
|
||||
if err = transaction.Commit(account); err != nil {
|
||||
@@ -622,36 +681,95 @@ func (a *ACME) LoadCertificateForDomains(domains []string) {
|
||||
|
||||
// Get provided certificate which check a domains list (Main and SANs)
|
||||
// from static and dynamic provided certificates
|
||||
func (a *ACME) getProvidedCertificate(domains []string) *tls.Certificate {
|
||||
log.Debugf("Look for provided certificate to validate %s...", domains)
|
||||
func (a *ACME) getProvidedCertificate(domains string) *tls.Certificate {
|
||||
log.Debugf("Looking for provided certificate to validate %s...", domains)
|
||||
cert := searchProvidedCertificateForDomains(domains, a.TLSConfig.NameToCertificate)
|
||||
if cert == nil && a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
||||
cert = searchProvidedCertificateForDomains(domains, a.dynamicCerts.Get().(*traefikTls.DomainsCertificates).Get().(map[string]*tls.Certificate))
|
||||
}
|
||||
log.Debugf("No provided certificate found for domains %s, get ACME certificate.", domains)
|
||||
if cert == nil {
|
||||
log.Debugf("No provided certificate found for domains %s, get ACME certificate.", domains)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
|
||||
func searchProvidedCertificateForDomains(domains []string, certs map[string]*tls.Certificate) *tls.Certificate {
|
||||
func searchProvidedCertificateForDomains(domain string, certs map[string]*tls.Certificate) *tls.Certificate {
|
||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||
providedCertMatch := false
|
||||
for k := range certs {
|
||||
selector := "^" + strings.Replace(k, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
for _, domainToCheck := range domains {
|
||||
providedCertMatch, _ = regexp.MatchString(selector, domainToCheck)
|
||||
if !providedCertMatch {
|
||||
for certDomains := range certs {
|
||||
domainCheck := false
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
domainCheck, _ = regexp.MatchString(selector, domain)
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if providedCertMatch {
|
||||
log.Debugf("Got provided certificate for domains %s", domains)
|
||||
return certs[k]
|
||||
|
||||
if domainCheck {
|
||||
log.Debugf("Domain %q checked by provided certificate %q", domain, certDomains)
|
||||
return certs[certDomains]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get provided certificate which check a domains list (Main and SANs)
|
||||
// from static and dynamic provided certificates
|
||||
func (a *ACME) getUncheckedDomains(domains []string, account *Account) []string {
|
||||
log.Debugf("Looking for provided certificate to validate %s...", domains)
|
||||
allCerts := make(map[string]*tls.Certificate)
|
||||
|
||||
// Get static certificates
|
||||
for domains, certificate := range a.TLSConfig.NameToCertificate {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
|
||||
// Get dynamic certificates
|
||||
if a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
||||
for domains, certificate := range a.dynamicCerts.Get().(*traefikTls.DomainsCertificates).Get().(map[string]*tls.Certificate) {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
}
|
||||
|
||||
// Get ACME certificates
|
||||
if account != nil {
|
||||
for domains, certificate := range account.DomainsCertificate.toDomainsMap() {
|
||||
allCerts[domains] = certificate
|
||||
}
|
||||
}
|
||||
|
||||
return searchUncheckedDomains(domains, allCerts)
|
||||
}
|
||||
|
||||
func searchUncheckedDomains(domains []string, certs map[string]*tls.Certificate) []string {
|
||||
uncheckedDomains := []string{}
|
||||
for _, domainToCheck := range domains {
|
||||
domainCheck := false
|
||||
for certDomains := range certs {
|
||||
domainCheck = false
|
||||
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||
domainCheck, _ = regexp.MatchString(selector, domainToCheck)
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if domainCheck {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !domainCheck {
|
||||
uncheckedDomains = append(uncheckedDomains, domainToCheck)
|
||||
}
|
||||
}
|
||||
if len(uncheckedDomains) == 0 {
|
||||
log.Debugf("No ACME certificate to generate for domains %q.", domains)
|
||||
} else {
|
||||
log.Debugf("Domains %q need ACME certificates generation for domains %q.", domains, strings.Join(uncheckedDomains, ","))
|
||||
}
|
||||
return uncheckedDomains
|
||||
}
|
||||
|
||||
func (a *ACME) getDomainsCertificates(domains []string) (*Certificate, error) {
|
||||
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
||||
log.Debugf("Loading ACME certificates %s...", domains)
|
||||
@@ -659,7 +777,7 @@ func (a *ACME) getDomainsCertificates(domains []string) (*Certificate, error) {
|
||||
certificate, failures := a.client.ObtainCertificate(domains, bundle, nil, OSCPMustStaple)
|
||||
if len(failures) > 0 {
|
||||
log.Error(failures)
|
||||
return nil, fmt.Errorf("Cannot obtain certificates %s+v", failures)
|
||||
return nil, fmt.Errorf("cannot obtain certificates %+v", failures)
|
||||
}
|
||||
log.Debugf("Loaded ACME certificates %s", domains)
|
||||
return &Certificate{
|
||||
|
||||
43
acme/acme_example.json
Normal file
43
acme/acme_example.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"Email": "test@traefik.io",
|
||||
"Registration": {
|
||||
"body": {
|
||||
"resource": "reg",
|
||||
"id": 3,
|
||||
"key": {
|
||||
"kty": "RSA",
|
||||
"n": "y5a71suIqvEtovDmDVQ3SSNagk5IVCFI_TvqWpEXSrdbcDE2C-PTEtEUJuLkYwygcpiWYbPmXgdS628vQCw5Uo4DeDyHiuysJOWBLaWow3p9goOdhnPbGBq0liIR9xXyRoctdipVk8UiO9scWsu4jMBM3sMr7_yBWPfYYiLEQmZGFO3iE7Oqr55h_kncHIj5lUQY1j_jkftqxlxUB5_0quyJ7l915j5QY--eY7h4GEhRvx0TlUpi-CnRtRblGeDDDilXZD6bQN2962WdKecsmRaYx-ttLz6jCPXz2VDJRWNcIS501ne2Zh3hzw_DS6IRd2GIia1Wg4sisi9epC9sumXPHi6xzR6-_i_nsFjdtTkUcV8HmorOYoc820KQVZaLScxa8e7-ixpOd6mr6AIbEf7dBAkb9f_iK3GwpqKD8yNcaj1EQgNSyJSjnKSulXI_GwkGnuXe00Qpb1a8ha5Z8yWg7XmZZnJyAZrmK60RfwRNQ1rO5ioerNUBJ2KYTYNzVjBdob9Ug6Cjh4bEKNNjqcbjQ50_Z97Vw40xzpDQ_fYllc6n92eSuv6olxFJTmK7EhHuanDzITngaqei3zL9RwQ7P-1jfEZ03qmGrQYYqXcsS46PQ8cE-frzY2mKp16pRNCG7-03gKVGV0JHyW1aYbevNUk7OumCAXhC2YOigBk",
|
||||
"e": "AQAB"
|
||||
},
|
||||
"contact": [
|
||||
"mailto:test@traefik.io"
|
||||
],
|
||||
"agreement": "http://boulder:4000/terms/v1"
|
||||
},
|
||||
"uri": "http://127.0.0.1:4000/acme/reg/3",
|
||||
"new_authzr_uri": "http://127.0.0.1:4000/acme/new-authz",
|
||||
"terms_of_service": "http://boulder:4000/terms/v1"
|
||||
},
|
||||
"PrivateKey": "MIIJJwIBAAKCAgEAy5a71suIqvEtovDmDVQ3SSNagk5IVCFI/TvqWpEXSrdbcDE2C+PTEtEUJuLkYwygcpiWYbPmXgdS628vQCw5Uo4DeDyHiuysJOWBLaWow3p9goOdhnPbGBq0liIR9xXyRoctdipVk8UiO9scWsu4jMBM3sMr7/yBWPfYYiLEQmZGFO3iE7Oqr55h/kncHIj5lUQY1j/jkftqxlxUB5/0quyJ7l915j5QY++eY7h4GEhRvx0TlUpi+CnRtRblGeDDDilXZD6bQN2962WdKecsmRaYx+ttLz6jCPXz2VDJRWNcIS501ne2Zh3hzw/DS6IRd2GIia1Wg4sisi9epC9sumXPHi6xzR6+/i/nsFjdtTkUcV8HmorOYoc820KQVZaLScxa8e7+ixpOd6mr6AIbEf7dBAkb9f/iK3GwpqKD8yNcaj1EQgNSyJSjnKSulXI/GwkGnuXe00Qpb1a8ha5Z8yWg7XmZZnJyAZrmK60RfwRNQ1rO5ioerNUBJ2KYTYNzVjBdob9Ug6Cjh4bEKNNjqcbjQ50/Z97Vw40xzpDQ/fYllc6n92eSuv6olxFJTmK7EhHuanDzITngaqei3zL9RwQ7P+1jfEZ03qmGrQYYqXcsS46PQ8cE+frzY2mKp16pRNCG7+03gKVGV0JHyW1aYbevNUk7OumCAXhC2YOigBkCAwEAAQKCAgA8XW1EuwTC6tAFSDhuK1JZNUpY6K05hMUHkQRj5jFpzgQmt/C2hc7H/YZkIVJmrA/G6sdsINNlffZwKH9yH6q/d6w/snLeFl7UcdhjmIL5sxAT6sKCY0fLVd/FxERfZvp3Pw2Tw+mr7v+/j7BQm6cU1M/2HRiiB9SydIqMTpKyvXB6NC6ceOFbQTL9GxlQvKyEPbS/kiH/3vRB7I5d1GfPZmNfcp6ark9X0my8VK4HRSo36H8t/OhrfLrZXvh/O82aHVf0OTv/d8AgU/jNu+XVXoXegUfWglQFDChJf1KuaE+g5w1tqgFDNgkGRD475soXA6xgZi0Iw/B9tN3zALzT4IiAW1q72feeTgKOMA2zGtKXxQZZSOV+DuWFZNz/tT7XqGQThqxM09CHv2WGOe80vobtegXYTUt90hysrqIZmBW5XYdzQlJh1KWTtfCaTrWd47kbGvhkEPc8aA3Ji4/AqfkVXiqwaLu+MSlgzPpRj7U7UAIDqnpZjgttgLp74Ujnk3bTaUzdyyNqYDBG3IFGr/Sv+2GQDAUn/PYRJKWr0BteqOzX9zvW3zY8g9CYVXfK/AW3RMWLV8ly6vH/gWqa9gEuzRNRlzjUU6/HCVbUx3UT8RMWH2TQ0uuQZr5JX1iTwjeeT0dEIly1NnRQC92wcrE4UUTBEF3krGVpDBf0AQKCAQEA4jB8w+2fwzbF8X+gCODcY7sTeJRunzGy+jbdaLkcThuylga+6W3ZgWx0BD30ql9K2mouCVu86fCTnBeXXEC3QoTdgw/EzJ83+4JU3QSDdzs9Ta9vLHyvrpUkQfZ8UZpeLLmFsmsBMbBbnfw0S1TzXDsgrAc+G4tia8nO/Iqu75kEMGzmHQAvmN3iSqc1aTS4qumbB19g+v+csq9NEht4F9jt39KotG+OD3MxCxtMu7vxAkJRjFFcgcbb2Rtqe/kQEKA1vLEAJg27lV4k8XibCSerVUR6IzT8WZHrNiXmpRguTLl2k8uFUdCOOx6aLGyRVJ6+8SgIsMR540vnxwQzEQKCAQEA5mu2wtWT19mvXopC3easPsXIPzc5oaRkqfWZYT1KHcVQ7NIXsE3vCjcf/3igZ8l/FVQ4G4fpk/GoTqlpV5Aq/JHCpVOR2O69uB+W4kWgliejpHvF9gszzAYnC8lIXqDbWiinBhmm3ii8sDGAoBaSDw5NMUq3mI+nd8zZ+jx1bLBczDafmQ0YKr8k0YaROxIgoBgDOQDdSqG387lwzpza2DKI5Al3HfS42zjT0RmBahPiuT2aEoUZmIYuvFY0fEjfkpbdvLyexHfZCILRUGlG1nAwASFg86lp+mFSBJ3E3cvbP0CpbFGxon5u4Ao3/7htoOh6huh7MQ91h41fv1hsiQKCAQAe7WRR4e7jYVzlbX7zV9Oqq0y5QwpxJ/mB7viNNiphn7Xmf5uhDU0dPjgK0HHgzdDNVpFe5DVLg4KbaDpg+dRU+xfSsNhG5kpgUGzMH67eIbJ7Kc64tX/MDkZ74nkTK1lPIjrer3TlV2jfjDmWR1JTPR51hzP9ziwx8tEjhM7woeqJuIoqUvkvHL+xV3WdIgFSFUkGVAtNpp/FauTN4gWktRupbAN3UH2LLUP6ccwnK0aD+Y9u8T0F3av33qDLvL1umIlgeI89pMkOXmYMwmHoeY0axpcwszECCkqwB7SmxEyoXv+Qq9ZZ3ntkKAYKpvmkKWSQUtoFWYgVBS727mMRAoIBABLdwusU/bPwuPEutObiWjwRiaHTbb6UbUGVQGe70vO5EjUxxorC9s2JUe9i+w9EakleyfFHIZLheHxoVp26yio/7QYIX6q5cYM/4uTH+qwQts9i6wSISkdsQYovguNsnEk3huVy+Dy8bSaoBvYUowTkkOF2Uq4FJRskBLz+ckbh8dcuqcaoUdA+Mk+NixqhE1bIYIssTPItZ5hnGJtyMGD/UkIJnF0ximk4r+8w/W2oDypHpvPZPg1E/1KgZE/Az7166NDpSL6haX3O6ECDPi+Uo/mTuBJ7TpgXm9WQ7WuTo3H8Y2LhFYBOhdmGPKuNeDxyjIW7R0rvDxp4MtzB6rECggEAJIl7/qp1lxUQPQJRTsEYBkOtdRw0IGG1Rcj0emhHaBN05c9opCy+Osb7mVeU5ZiULe5kD02phL+36pEumprz7QzN46Y5pZc8AQ2W/QkeL4Wo9U9QzczvQQzc1EqrBkzvQTZtBhn4DRzz0IuTn1beVyHtBZeNpBFgMQFv9VYQuUNwFoTOkkQrBRnYbXH6KEnhF3c/1Hzi4KHVdHdfZ3LH7KFQJ34xio0q2tWQSQYeybmwOXdd9sxpz/Y4KBS9fqm7UrwnPK8yuOc05HLEaws+1iam5YyJprlQo3mGKe0wRztwn44HDeQr70LlFm0lzigVAv0hSiWO1Q5hJL7nDu8m/Q==",
|
||||
"DomainsCertificate": {
|
||||
"Certs": [
|
||||
{
|
||||
"Domains": {
|
||||
"Main": "local1.com",
|
||||
"SANs": [
|
||||
"test1.local1.com",
|
||||
"test2.local1.com"
|
||||
]
|
||||
},
|
||||
"Certificate": {
|
||||
"Domain": "local1.com",
|
||||
"CertURL": "http://127.0.0.1:4000/acme/cert/ffc4f3f14def9ee6ec6a0522b5c0baa3379d",
|
||||
"CertStableURL": "",
|
||||
"PrivateKey": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBdVNoTTR4enF6cE5YcFNaNnAvZnQrRmt5VmgyK1BSZXJUelV0OERRSng2UkVjQS9FCnN2RnNIVmNOSkZMS2twYTNlOEd3SUZBakJQNnJPK3hoR1JjWlJrdENON1gyOW5LZFhGbHZkYzJxd0hyTFF5WWkKTTB3ODhTck41VERiNi96TWU2dTB0dERiYWtDbDd6ZEJKUXJ6a1h5ZU1MeVkzTUs3aVkrMHpwL2JqMVhvbk5DdQpaQStkZ3hsMVNrV01DVUYvQk9HNWFyT1hwb0x4S0dQWGdzV3hOTVNLVmJKSHczL3ZqNTViZU92Um5lT3BNWlhvCmMwOWpZT3VBakNka1Z5czBSWHJLNWNCRDRMbVRXdnN4MFdTK2VMVHlGTTdQTHVZM3lEWkNNWEhjVmlqRHhnbFMKYjB1ZVRQcGFUWEQwYkxqZ0RNOUVEdE15ZEJzMUNPWlpPWG9ickN5Q2I1eWxTOFdVd1NzVXM1UldxZnlVbnAvcgpSNGx2c2RZOWRVZjRPdkNMVnJvWWk5NWFGc1Zxa0xLOExuL0Eyc3kxYWlDTnR4RmpKOXRXbWU0V0NhdzRoU0YvCkR4NWVNNWNYR2JSYXduVlZJQlZXeHhzNTBPMFJlUWRvbXBQZEFNS1RDWk9SRmxYaDdOWTdxQVdWRGtpdzhyam8Kekd3Ni9XdjlOR3hTNTliKzc0YVAxcjBxOTZ2RS9Rdi8zTCtjbjhiN0lBLytPYmFKdzhIT3RGbXc4RjBxQkN3MAprYWVVSloxb1JueGFYQUo4RHhHREpFOVdNUzh0QmJtVm16YkxoRkMzeDdVc0xGeTBrSzh1SFBFT3dQb2NKNUFUCkE1UHBvclNEMmFleHA0Z3VqYVp5c1JManpmY0dnaTdva0JFNlZVNWVqRE1iYS9lNERQNEJQUVg5VmtVQ0F3RUEKQVFLQ0FnQmZjMWdYcUp1ZmZMT3REcVlpbXh4UmIrSVVKT2NpWldaSndmZDVvY244NGtEcHFDZFZ2RUZvNnF4NgpzamQ5MURhb2xOUHdCSC9aSGxRMTR3aTNQNEluQzdzS0wwTXVEeTN5SXFUa0RPOWVwSzdPWWdVMWZyTFgvS0lCCjZlc2x2Ny9HYldFTzhhSjdKdktqM0U4NEFtcEg4UDgzenJIYTlJUnJTT3NEcmNNcEpEZHpSOXp1OW1IVDZMYmYKWC9UdC9KYTNkSW42YUxUZ0FSYkRKSjAvN0J3TFFOcXpqT0dUOWdzUWRhbGdMK2x5eEo4L1ViRndhRmVwNmgzdApvbzBHcHQ0ZWgwdTdueDhlNVd3Q2RnWmJsTnpnS3grMC9Gd3dLRHhQZVRFc2ZpOEJONmlkR2NjbVdzd3prTWdtCnJmbERaeGNSWTNRSlZIVHBCL0dTTWZXRFBPQ3dRdGltQk1WN3kxM2hPMTdPWXpSNDBMZnpUalJBbmtna2V2eWYKcFowb3dLR3o4QS9haHhRWWJmYVQ5VEhXV0wrYUpYeUhFanBKckp5aTg3UExVbzhsOFVydU56MDRWNXpLOFJPbgo2cG9EWmVtbm1EYWRlU09pK3hZRWlGT1NwSXNWbzlpcm9jUGFKN2YzYWpiNUU4RHpuN1o1MmhzL2R6akpLcFZJCm5mVDFkUU9SZEowSXRUNlRlQ2RTL0dpS25IS1RtNjR2T21IbmlJcm8rUGRhUmFjV0IrTUJ0VytRd0cyUStyRGkKc3g4NlpQbHRpTVpLMDZ5TVlyVHZUdGk2aFVGaUY5cWh4b3RGazdNQkNrZlIwYUVhaUREQUpKNm1jb1lpRUQ2QgpBVGJhVmpVaGNaUiswYkRST25PN0ozRk5rZmx3K2dMaVhvcXFRRW9pU2ZWb2h5SWY3UUtDQVFFQThjYTM5K0g4CjN3L2Qrcm0yUGNhM0RMQnBYaWU4Z3ZYcGpjazVYSkpvSGVmbnJjZWQrcFpXaTZEYncwYld0MEdtYkxmVjJNSlAKV2I1aTZzSXhmdkN3YlFqbHY0UnExMVA5ZEswT3poMnVpKzZ6cXVBMG5YTVcrN0lJS0cvdDhmS2NJZGRRNnRGcwpFclFVTFBDak56ODA2cHBiSlhPRmVvMW1BK293TGhHNlA3dDhCdlZHSk1NaTNxejNlSUNuVVE2eDNFY01ITXNuClhrM21DUzI1WUZaNk96cytFK254cGVraTAzZmQwblp3UE1jdElHZys1c3hleE9zREsrTHlvb2FqQnc5N0oyUzIKcUNNWXFtT0tLcmxEQ3Y1WmQ4dlZLN3hXVmpKRVhGTTNMZ2pieHBRcCtuVXNVVWxwS01LOVlGS0lRREl0RU9aMApWcWExTXJaOElzN1l5d0tDQVFFQXhBemZIa2pIVGlvTHdZbG5EcEk0MWlOTDh5Y0ZBallrTC94dWhPU2tlVkE4CjdRWDZPZUpDekR3Z0FUYXVqOWR6Y0wwby9yTndWV0xWcnQ3OXk3YnJvVDdFREZKWVNTY25GRXNMTlVWSXRncGkKckNSUXJTL1F2TkVGTmE5K0pRc1dmYkdBNHdIUTFaSjI4MFp1cWMvNlEyUi9kZVh3cUZBQVBHN2NIcEhHWlR6ZQoyRmFRUHFLRkV4WlEyZkpvRys0SVBRNHVQVERybXlGMmVUWXk2T3BaaDBHbWJRYlVTa1dFWDlQRmF1cHJIWVdGCk8wK25DaVVPNVRaMFZoaGR2dUNKMWdPclZHYzhBUlJtUVZ1aUNEWTZCaGlvVTU0ZmZsSXlDTXZ5a3MwcmRXZ3MKWVJ2TmN4TXNlRGJpTDRKSURkMHhiN1d4VUdmVjRVNHZPMks5Vms1N0x3S0NBUUVBMkd1eE1jcXd1RnRUc0tPYwpaaUFDcXZFZTRKRmhSVGtySHlnSW1MelZSaS9ZU3M1c3MycnZmWDA0T3N5bVZ0UUZUVHdoeUMzbktjWXFkVW52ClZGblBFMHJyblV2Qzk0elBUQ205SHZPaTBzK1JORndOdlFMUWgrME5NR1ZBOFZyaU44aXRQZ1RJWU5XaFdianQKNFA1TE45V0QwVHBmT1J4cFBRZmNxT0JsZjdjcmhtNzNvdUNwemZtMmE3OStCaWpKUFF5NzR1cFhDeXRmeHNlUApNSlU0Uk56NjdJaDFMclpKM2xGbDFvYitZT2xKazhDOHpZd1RLT0hWck9zeGxobyt4SXN2Q2t3MDFMelZ6Mi9hCnRmT3Y5NTlHSnQzbXE0ZWpJUFZPQy9iUlpmdTMvMEdSY2dpQTZ5SnpaM0VxWTVaOU1EbTU3VzdjcE5RRlRxZmEKNXEyUmtRS0NBUUErNGhZSzQ3TXg2aUNkTWxKaEJSdS82OUJucktOWm96NFdPalRFNFlXejk3MmpGU0Mrd2tsRQpzeUJjNDBvNGp4WFRHb2wwc04rZU03WndnY3dNTko3OXVHRXZ4cFhVMlA4YTdqc3BHaEVKZXVsTlo5U015R0orCnZkaWE4TEJZZDJiK2FCbjhOay9pd1Rqd0xTNC92NXI1Vk5uaFdpRElDK2tYZVVPWGRwQ1pWbDN3TEV2V0cxRHQKMzJHTmxzZzM5VENsVE5BZUJudjc1VTdYOEQrQ0gvRVpoa0E0aGxFL2hXN0JRZTczclRzd1creHhLc3BjWWFpVwpjdEg3NzVMYUw3Rm1lUVRTYk01OVZpcTZXZ2J0OVY3Rko5R09DSkQzZHF2ZjBITDlEVndjSzQ3WWt3OWlFc3RYCnY5cnEvREhhYUpGNzBGNlFlTTNNbDhSa212WTZJYkEzQW9JQkFRRGt6RmZLeG9HQ3dWUDlua3k4NmFQSjFvd2kKc2FDZEx6RjRWTENRZzkrUXJITzEyY0p5MFFQUnJ2cUQyMGp1cDFlOWJhWVZzbkdYc1FZTFg2NVR6UzJSSCtlSAp6S0NPTTdnMVE3djMxNWpjMDMvN1lQck4rb3RrV0VBOUkyaDZjUE1vY3c0aERTNk02OFlxQVlKTS9RclVhenZhCnhBTFJaZEVkQW1xWDA4VHhuY1hRUEVxYkk0ZnlSZ2pVM1BYR3RRaFFFbERpR2kwbThjQTJNTXdsR1RmbTdOSXgKaENjZ2ZkL296TEp2VUhiMkxLRi82cXEySmJVRHlOMkVoK0xSZUJjdnp6Y1grZE5MdGQxY0Uvcm1SM2hMbWxmNgo3KzRpTVMxK0t1eWV3VlJVUEE1c1F1aUYyVUVoeEs1MUpZK1FpOG9HbERKdGRrOXB3QlZNN1F0WW9KVEwKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K",
|
||||
"Certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZvakNDQklxZ0F3SUJBZ0lUQVAvRTgvRk43NTdtN0dvRklyWEF1cU0zblRBTkJna3Foa2lHOXcwQkFRc0YKQURBZk1SMHdHd1lEVlFRRERCUm9NbkJ3ZVNCb01tTnJaWElnWm1GclpTQkRRVEFlRncweE9EQXhNVFV3TnpJNQpNREJhRncweE9EQTBNVFV3TnpJNU1EQmFNRVF4RXpBUkJnTlZCQU1UQ214dlkyRnNNUzVqYjIweExUQXJCZ05WCkJBVVRKR1ptWXpSbU0yWXhOR1JsWmpsbFpUWmxZelpoTURVeU1tSTFZekJpWVdFek16YzVaRENDQWlJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnSVBBRENDQWdvQ2dnSUJBTGtvVE9NYzZzNlRWNlVtZXFmMzdmaFpNbFlkdmowWApxMDgxTGZBMENjZWtSSEFQeExMeGJCMVhEU1JTeXBLV3QzdkJzQ0JRSXdUK3F6dnNZUmtYR1VaTFFqZTE5dlp5Cm5WeFpiM1hOcXNCNnkwTW1Jak5NUFBFcXplVXcyK3Y4ekh1cnRMYlEyMnBBcGU4M1FTVUs4NUY4bmpDOG1OekMKdTRtUHRNNmYyNDlWNkp6UXJtUVBuWU1aZFVwRmpBbEJmd1RodVdxemw2YUM4U2hqMTRMRnNUVEVpbFd5UjhOLwo3NCtlVzNqcjBaM2pxVEdWNkhOUFkyRHJnSXduWkZjck5FVjZ5dVhBUStDNWsxcjdNZEZrdm5pMDhoVE96eTdtCk44ZzJRakZ4M0ZZb3c4WUpVbTlMbmt6NldrMXc5R3k0NEF6UFJBN1RNblFiTlFqbVdUbDZHNndzZ20rY3BVdkYKbE1FckZMT1VWcW44bEo2ZjYwZUpiN0hXUFhWSCtEcndpMWE2R0l2ZVdoYkZhcEN5dkM1L3dOck10V29namJjUgpZeWZiVnBudUZnbXNPSVVoZnc4ZVhqT1hGeG0wV3NKMVZTQVZWc2NiT2REdEVYa0hhSnFUM1FEQ2t3bVRrUlpWCjRleldPNmdGbFE1SXNQSzQ2TXhzT3Yxci9UUnNVdWZXL3UrR2o5YTlLdmVyeFAwTC85eS9uSi9HK3lBUC9qbTIKaWNQQnpyUlpzUEJkS2dRc05KR25sQ1dkYUVaOFdsd0NmQThSZ3lSUFZqRXZMUVc1bFpzMnk0UlF0OGUxTEN4Ywp0SkN2TGh6eERzRDZIQ2VRRXdPVDZhSzBnOW1uc2FlSUxvMm1jckVTNDgzM0JvSXU2SkFST2xWT1hvd3pHMnYzCnVBeitBVDBGL1ZaRkFnTUJBQUdqZ2dHd01JSUJyREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdIUVlEVlIwbEJCWXcKRkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk5LZQpBVUZYc2Z2N2lML0lYVVBXdzY2ZU5jQnhNQjhHQTFVZEl3UVlNQmFBRlB0NFR4TDVZQldETEo4WGZ6UVpzeTQyCjZrR0pNR1lHQ0NzR0FRVUZCd0VCQkZvd1dEQWlCZ2dyQmdFRkJRY3dBWVlXYUhSMGNEb3ZMekV5Tnk0d0xqQXUKTVRvME1EQXlMekF5QmdnckJnRUZCUWN3QW9ZbWFIUjBjRG92THpFeU55NHdMakF1TVRvME1EQXdMMkZqYldVdgphWE56ZFdWeUxXTmxjblF3T1FZRFZSMFJCREl3TUlJS2JHOWpZV3d4TG1OdmJZSVFkR1Z6ZERFdWJHOWpZV3d4CkxtTnZiWUlRZEdWemRESXViRzlqWVd3eExtTnZiVEFuQmdOVkhSOEVJREFlTUJ5Z0dxQVloaFpvZEhSd09pOHYKWlhoaGJYQnNaUzVqYjIwdlkzSnNNR0VHQTFVZElBUmFNRmd3Q0FZR1o0RU1BUUlCTUV3R0F5b0RCREJGTUNJRwpDQ3NHQVFVRkJ3SUJGaFpvZEhSd09pOHZaWGhoYlhCc1pTNWpiMjB2WTNCek1COEdDQ3NHQVFVRkJ3SUNNQk1NCkVVUnZJRmRvWVhRZ1ZHaHZkU0JYYVd4ME1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ3A0Q2FxZlR4THNQTzQKS2JueDJZdEc4bTN3MC9keTVVR1VRNjZHbGxPVTk0L2I0MmNhbTRuNUZrTWlpZ01IaUx4c2JZVXh0cDZKQ3R5cQpLKzFNcDFWWEtSTTVKbFBTNWRIaWhxdHk1U3BrTUhjampwQSs3U2YyVWtoNmpKRWYxTUVJY2JnWnpJRk5IT0hYClVUUUppVFhKcno3blJDZnlQWFZtbWErUGtIRlU4R0VEVzJGOVptU1kzVFBiQWhiWkV2UkZubjUrR1lxbkZuancKWWw3Y0I2MXYwRzVpOGQwbnVvbTB4a2hiNTU3Y3BiZHhLblhsaFU4N2RZSTR5SUdPdUFGUWpYcXFXN2NIZCtXUQpWSDB2dFA3cEgrRmt2YnY4WkkxMHMrNU5ZcCtzZjFQZGQxekJsRmdNSGF3dnFFYUg3SU9sejdkajlCdmtVc0dpClhxQWVqQnFPCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVpakNDQTNLZ0F3SUJBZ0lDRWswd0RRWUpLb1pJaHZjTkFRRUxCUUF3S3pFcE1DY0dBMVVFQXd3Z1kyRmoKYTJ4cGJtY2dZM0o1Y0hSdlozSmhjR2hsY2lCbVlXdGxJRkpQVDFRd0hoY05NVFV4TURJeE1qQXhNVFV5V2hjTgpNakF4TURFNU1qQXhNVFV5V2pBZk1SMHdHd1lEVlFRREV4Um9ZWEJ3ZVNCb1lXTnJaWElnWm1GclpTQkRRVENDCkFTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUlLUjNtYUJjVVNzbmNYWXpRVDEzRDUKTnIrWjNtTHhNTWgzVFVkdDZzQUNtcWJKMGJ0UmxnWGZNdE5MTTJPVTFJNmEzSnUrdElaU2RuMnYyMUpCd3Z4VQp6cFpRNHp5MmNpbUlpTVFEWkNRSEp3ekM5R1puOEhhVzA5MWl6OUgwR28zQTdXRFh3WU5tc2RMTlJpMDBvMTRVCmpvYVZxYVBzWXJaV3ZSS2FJUnFhVTBoSG1TMEFXd1FTdk4vOTNpTUlYdXlpd3l3bWt3S2JXbm54Q1EvZ3NjdEsKRlV0Y05yd0V4OVdnajZLbGh3RFR5STFRV1NCYnhWWU55VWdQRnpLeHJTbXdNTzB5TmZmN2hvK1FUOXg1K1kvNwpYRTU5UzRNYzRaWHhjWEtldy9nU2xOOVU1bXZUK0QyQmhEdGtDdXBkZnNaTkNRV3AyN0ErYi9EbXJGSTlOcXNDCkF3RUFBYU9DQWNJd2dnRytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3UXdZRFZSMGVCRHd3T3FFNE1BYUMKQkM1dGFXd3dDb2NJQUFBQUFBQUFBQUF3SW9jZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQpBQUFBQUFBd0RnWURWUjBQQVFIL0JBUURBZ0dHTUg4R0NDc0dBUVVGQndFQkJITXdjVEF5QmdnckJnRUZCUWN3CkFZWW1hSFIwY0RvdkwybHpjbWN1ZEhKMWMzUnBaQzV2WTNOd0xtbGtaVzUwY25WemRDNWpiMjB3T3dZSUt3WUIKQlFVSE1BS0dMMmgwZEhBNkx5OWhjSEJ6TG1sa1pXNTBjblZ6ZEM1amIyMHZjbTl2ZEhNdlpITjBjbTl2ZEdOaAplRE11Y0Rkak1COEdBMVVkSXdRWU1CYUFGT21rUCs2ZXBlYnkxZGQ1WUR5VHBpNGtqcGVxTUZRR0ExVWRJQVJOCk1Fc3dDQVlHWjRFTUFRSUJNRDhHQ3lzR0FRUUJndDhUQVFFQk1EQXdMZ1lJS3dZQkJRVUhBZ0VXSW1oMGRIQTYKTHk5amNITXVjbTl2ZEMxNE1TNXNaWFJ6Wlc1amNubHdkQzV2Y21jd1BBWURWUjBmQkRVd016QXhvQytnTFlZcgphSFIwY0RvdkwyTnliQzVwWkdWdWRISjFjM1F1WTI5dEwwUlRWRkpQVDFSRFFWZ3pRMUpNTG1OeWJEQWRCZ05WCkhRNEVGZ1FVKzNoUEV2bGdGWU1zbnhkL05CbXpMamJxUVlrd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFBMFkKQWVMWE9rbHg0aGhDaWtVVWwrQmRuRmZuMWcwVzVBaVFMVk5JT0w2UG5xWHUwd2puaE55aHFkd25maFlNbm95NAppZFJoNGxCNnB6OEdmOXBubExkL0RuV1NWM2dTKy9JL21BbDFkQ2tLYnk2SDJWNzkwZTZJSG1JSzJLWW0zam0rClUrK0ZJZEdwQmRzUVRTZG1pWC9yQXl1eE1ETTBhZE1rTkJ3VGZRbVpRQ3o2bkdIdzFRY1NQWk12WnBzQzhTa3YKZWt6eHNqRjFvdE9yTVVQTlBRdnRUV3JWeDhHbFIycWZ4LzR4YlFhMXYyZnJOdkZCQ21PNTlnb3oram5XdmZUdApqMk5qd0RaN3ZsTUJzUG0xNmRiS1lDODQwdXZSb1pqeHFzZGMzQ2hDWmpxaW1GcWxORy94b1BBOCtkVGljWnpDClhFOWlqUEljdlc2eTFhYTNiR3c9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ChallengeCerts": {}
|
||||
}
|
||||
@@ -267,7 +267,7 @@ cijFkALeQp/qyeXdFld2v9gUN3eCgljgcl0QweRoIc=---`)
|
||||
}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
a := ACME{DNSProvider: "manual", DelayDontCheckDNS: 10, CAServer: ts.URL}
|
||||
a := ACME{DNSChallenge: &DNSChallenge{Provider: "manual", DelayBeforeCheck: 10}, CAServer: ts.URL}
|
||||
|
||||
client, err := a.buildACMEClient(account)
|
||||
if err != nil {
|
||||
@@ -281,7 +281,7 @@ cijFkALeQp/qyeXdFld2v9gUN3eCgljgcl0QweRoIc=---`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcme_getProvidedCertificate(t *testing.T) {
|
||||
func TestAcme_getUncheckedCertificates(t *testing.T) {
|
||||
mm := make(map[string]*tls.Certificate)
|
||||
mm["*.containo.us"] = &tls.Certificate{}
|
||||
mm["traefik.acme.io"] = &tls.Certificate{}
|
||||
@@ -289,9 +289,36 @@ func TestAcme_getProvidedCertificate(t *testing.T) {
|
||||
a := ACME{TLSConfig: &tls.Config{NameToCertificate: mm}}
|
||||
|
||||
domains := []string{"traefik.containo.us", "trae.containo.us"}
|
||||
certificate := a.getProvidedCertificate(domains)
|
||||
assert.NotNil(t, certificate)
|
||||
uncheckedDomains := a.getUncheckedDomains(domains, nil)
|
||||
assert.Empty(t, uncheckedDomains)
|
||||
domains = []string{"traefik.acme.io", "trae.acme.io"}
|
||||
certificate = a.getProvidedCertificate(domains)
|
||||
uncheckedDomains = a.getUncheckedDomains(domains, nil)
|
||||
assert.Len(t, uncheckedDomains, 1)
|
||||
domainsCertificates := DomainsCertificates{Certs: []*DomainsCertificate{
|
||||
{
|
||||
tlsCert: &tls.Certificate{},
|
||||
Domains: Domain{
|
||||
Main: "*.acme.wtf",
|
||||
SANs: []string{"trae.acme.io"},
|
||||
},
|
||||
},
|
||||
}}
|
||||
account := Account{DomainsCertificate: domainsCertificates}
|
||||
uncheckedDomains = a.getUncheckedDomains(domains, &account)
|
||||
assert.Empty(t, uncheckedDomains)
|
||||
}
|
||||
|
||||
func TestAcme_getProvidedCertificate(t *testing.T) {
|
||||
mm := make(map[string]*tls.Certificate)
|
||||
mm["*.containo.us"] = &tls.Certificate{}
|
||||
mm["traefik.acme.io"] = &tls.Certificate{}
|
||||
|
||||
a := ACME{TLSConfig: &tls.Config{NameToCertificate: mm}}
|
||||
|
||||
domain := "traefik.containo.us"
|
||||
certificate := a.getProvidedCertificate(domain)
|
||||
assert.NotNil(t, certificate)
|
||||
domain = "trae.acme.io"
|
||||
certificate = a.getProvidedCertificate(domain)
|
||||
assert.Nil(t, certificate)
|
||||
}
|
||||
|
||||
92
acme/challenge_http_provider.go
Normal file
92
acme/challenge_http_provider.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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 = (*challengeHTTPProvider)(nil)
|
||||
|
||||
type challengeHTTPProvider struct {
|
||||
store cluster.Store
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
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
|
||||
if result, ok = account.HTTPChallenge[token][domain]; !ok {
|
||||
return fmt.Errorf("cannot find challenge for token %v", token)
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting challenge for token: %v", err)
|
||||
return []byte{}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
delete(account.HTTPChallenge[token], domain)
|
||||
}
|
||||
if len(account.HTTPChallenge[token]) == 0 {
|
||||
delete(account.HTTPChallenge, token)
|
||||
}
|
||||
}
|
||||
return transaction.Commit(account)
|
||||
}
|
||||
|
||||
func (c *challengeHTTPProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return 60 * time.Second, 5 * time.Second
|
||||
}
|
||||
@@ -23,15 +23,15 @@ import (
|
||||
"github.com/xenolf/lego/acme"
|
||||
)
|
||||
|
||||
var _ acme.ChallengeProviderTimeout = (*challengeProvider)(nil)
|
||||
var _ acme.ChallengeProviderTimeout = (*challengeTLSProvider)(nil)
|
||||
|
||||
type challengeProvider struct {
|
||||
type challengeTLSProvider struct {
|
||||
store cluster.Store
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *challengeProvider) getCertificate(domain string) (cert *tls.Certificate, exists bool) {
|
||||
log.Debugf("Challenge GetCertificate %s", domain)
|
||||
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
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func (c *challengeProvider) getCertificate(domain string) (cert *tls.Certificate
|
||||
return result, true
|
||||
}
|
||||
|
||||
func (c *challengeProvider) Present(domain, token, keyAuth string) error {
|
||||
func (c *challengeTLSProvider) Present(domain, token, keyAuth string) error {
|
||||
log.Debugf("Challenge Present %s", domain)
|
||||
cert, _, err := tlsSNI01ChallengeCert(keyAuth)
|
||||
if err != nil {
|
||||
@@ -88,7 +88,7 @@ func (c *challengeProvider) Present(domain, token, keyAuth string) error {
|
||||
return transaction.Commit(account)
|
||||
}
|
||||
|
||||
func (c *challengeProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
func (c *challengeTLSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
log.Debugf("Challenge CleanUp %s", domain)
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
@@ -101,7 +101,7 @@ func (c *challengeProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
return transaction.Commit(account)
|
||||
}
|
||||
|
||||
func (c *challengeProvider) Timeout() (timeout, interval time.Duration) {
|
||||
func (c *challengeTLSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return 60 * time.Second, 5 * time.Second
|
||||
}
|
||||
|
||||
41
acme/localStore_test.go
Normal file
41
acme/localStore_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
acmeFile := "./acme_example.json"
|
||||
|
||||
folder, prefix := filepath.Split(acmeFile)
|
||||
tmpFile, err := ioutil.TempFile(folder, prefix)
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
fileContent, err := ioutil.ReadFile(acmeFile)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tmpFile.Write(fileContent)
|
||||
|
||||
localStore := NewLocalStore(tmpFile.Name())
|
||||
obj, err := localStore.Load()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
account, ok := obj.(*Account)
|
||||
if !ok {
|
||||
t.Error("Object is not an ACME Account")
|
||||
}
|
||||
|
||||
if len(account.DomainsCertificate.Certs) != 1 {
|
||||
t.Errorf("Must found %d and found %d certificates in Account", 3, len(account.DomainsCertificate.Certs))
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type DashboardHandler struct{}
|
||||
func (g DashboardHandler) AddRoutes(router *mux.Router) {
|
||||
// Expose dashboard
|
||||
router.Methods(http.MethodGet).Path("/").HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
||||
http.Redirect(response, request, "/dashboard/", 302)
|
||||
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"})))
|
||||
|
||||
@@ -19,9 +19,9 @@ type Handler struct {
|
||||
Dashboard bool `description:"Activate dashboard" export:"true"`
|
||||
Debug bool `export:"true"`
|
||||
CurrentConfigurations *safe.Safe
|
||||
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
|
||||
Stats *thoas_stats.Stats
|
||||
StatsRecorder *middlewares.StatsRecorder
|
||||
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
|
||||
Stats *thoas_stats.Stats `json:"-"`
|
||||
StatsRecorder *middlewares.StatsRecorder `json:"-"`
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -135,7 +135,7 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
method = "{{getLoadBalancerMethod $backend}}"
|
||||
sticky = {{getSticky $backend}}
|
||||
{{if hasStickinessLabel $backend}}
|
||||
[backends.backend-{{$backendName}}.loadBalancer.stickiness]
|
||||
[backends.backend-{{$backendName}}.loadbalancer.stickiness]
|
||||
cookieName = "{{getStickinessCookieName $backend}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -172,7 +172,6 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}"]
|
||||
backend = "backend-{{getServiceBackend $container $serviceName}}"
|
||||
passHostHeader = {{getServicePassHostHeader $container $serviceName}}
|
||||
redirect = "{{getServiceRedirect $container $serviceName}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
@@ -185,14 +184,21 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
basicAuth = [{{range getServiceBasicAuth $container $serviceName}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
|
||||
{{if hasServiceRedirect $container $serviceName}}
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".redirect]
|
||||
entryPoint = "{{getServiceRedirectEntryPoint $container $serviceName}}"
|
||||
regex = "{{getServiceRedirectRegex $container $serviceName}}"
|
||||
replacement = "{{getServiceRedirectReplacement $container $serviceName}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
rule = "{{getServiceFrontendRule $container $serviceName}}"
|
||||
{{end}}
|
||||
{{else}}
|
||||
[frontends."frontend-{{$frontend}}"]
|
||||
backend = "backend-{{getBackend $container}}"
|
||||
passHostHeader = {{getPassHostHeader $container}}
|
||||
redirect = "{{getRedirect $container}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
@@ -205,6 +211,15 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
basicAuth = [{{range getBasicAuth $container}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $container}}
|
||||
[frontends."frontend-{{$frontend}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $container}}"
|
||||
regex = "{{getRedirectRegex $container}}"
|
||||
replacement = "{{getRedirectReplacement $container}}"
|
||||
{{end}}
|
||||
|
||||
{{ if hasHeaders $container}}
|
||||
[frontends."frontend-{{$frontend}}".headers]
|
||||
{{if hasSSLRedirectHeaders $container}}
|
||||
SSLRedirect = {{getSSLRedirectHeaders $container}}
|
||||
@@ -251,6 +266,16 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
{{if hasIsDevelopmentHeaders $container}}
|
||||
IsDevelopment = {{getIsDevelopmentHeaders $container}}
|
||||
{{end}}
|
||||
{{if hasAllowedHostsHeaders $container}}
|
||||
AllowedHosts = [{{range getAllowedHostsHeaders $container}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
{{end}}
|
||||
{{if hasHostsProxyHeaders $container}}
|
||||
HostsProxyHeaders = [{{range getHostsProxyHeaders $container}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
{{end}}
|
||||
{{if hasRequestHeaders $container}}
|
||||
[frontends."frontend-{{$frontend}}".headers.customrequestheaders]
|
||||
{{range $k, $v := getRequestHeaders $container}}
|
||||
@@ -263,24 +288,14 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||
{{$k}} = "{{$v}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if hasAllowedHostsHeaders $container}}
|
||||
[frontends."frontend-{{$frontend}}".headers.AllowedHosts]
|
||||
{{range getAllowedHostsHeaders $container}}
|
||||
"{{.}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if hasHostsProxyHeaders $container}}
|
||||
[frontends."frontend-{{$frontend}}".headers.HostsProxyHeaders]
|
||||
{{range getHostsProxyHeaders $container}}
|
||||
"{{.}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if hasSSLProxyHeaders $container}}
|
||||
[frontends."frontend-{{$frontend}}".headers.SSLProxyHeaders]
|
||||
{{range $k, $v := getSSLProxyHeaders $container}}
|
||||
{{$k}} = "{{$v}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"]
|
||||
rule = "{{getFrontendRule $container}}"
|
||||
{{end}}
|
||||
@@ -414,13 +429,24 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
|
||||
backend = "{{$frontend.Backend}}"
|
||||
priority = {{$frontend.Priority}}
|
||||
passHostHeader = {{$frontend.PassHostHeader}}
|
||||
redirect = "{{$frontend.Redirect}}"
|
||||
entryPoints = [{{range $frontend.EntryPoints}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
basicAuth = [{{range $frontend.BasicAuth}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
whitelistSourceRange = [{{range $frontend.WhitelistSourceRange}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if $frontend.Redirect}}
|
||||
[frontends."{{$frontendName}}".redirect]
|
||||
entryPoint = "{{$frontend.Redirect.EntryPoint}}"
|
||||
regex = "{{$frontend.Redirect.Regex}}"
|
||||
replacement = "{{$frontend.Redirect.Replacement}}"
|
||||
{{end}}
|
||||
|
||||
{{ if $frontend.Headers }}
|
||||
[frontends."{{$frontendName}}".headers]
|
||||
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
|
||||
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
|
||||
@@ -437,40 +463,45 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
|
||||
PublicKey = "{{$frontend.Headers.PublicKey}}"
|
||||
ReferrerPolicy = "{{$frontend.Headers.ReferrerPolicy}}"
|
||||
IsDevelopment = {{$frontend.Headers.IsDevelopment}}
|
||||
{{if $frontend.Headers.CustomRequestHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.customrequestheaders]
|
||||
|
||||
{{if $frontend.Headers.AllowedHosts}}
|
||||
AllowedHosts = [{{range $frontend.Headers.AllowedHosts}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
{{end}}
|
||||
|
||||
{{if $frontend.Headers.HostsProxyHeaders}}
|
||||
HostsProxyHeaders = [{{range $frontend.Headers.HostsProxyHeaders}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
{{end}}
|
||||
|
||||
{{if $frontend.Headers.CustomRequestHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.customrequestheaders]
|
||||
{{range $k, $v := $frontend.Headers.CustomRequestHeaders}}
|
||||
{{$k}} = "{{$v}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if $frontend.Headers.CustomResponseHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.customresponseheaders]
|
||||
{{end}}
|
||||
|
||||
{{if $frontend.Headers.CustomResponseHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.customresponseheaders]
|
||||
{{range $k, $v := $frontend.Headers.CustomResponseHeaders}}
|
||||
{{$k}} = "{{$v}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if $frontend.Headers.AllowedHosts}}
|
||||
[frontends."{{$frontendName}}".headers.AllowedHosts]
|
||||
{{range $frontend.Headers.AllowedHosts}}
|
||||
"{{.}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if $frontend.Headers.HostsProxyHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.HostsProxyHeaders]
|
||||
{{range $frontend.Headers.HostsProxyHeaders}}
|
||||
"{{.}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if $frontend.Headers.SSLProxyHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.SSLProxyHeaders]
|
||||
{{end}}
|
||||
|
||||
{{if $frontend.Headers.SSLProxyHeaders}}
|
||||
[frontends."{{$frontendName}}".headers.SSLProxyHeaders]
|
||||
{{range $k, $v := $frontend.Headers.SSLProxyHeaders}}
|
||||
{{$k}} = "{{$v}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{range $routeName, $route := $frontend.Routes}}
|
||||
[frontends."{{$frontendName}}".routes."{{$routeName}}"]
|
||||
|
||||
{{range $routeName, $route := $frontend.Routes}}
|
||||
[frontends."{{$frontendName}}".routes."{{$routeName}}"]
|
||||
rule = "{{$route.Rule}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
`)
|
||||
|
||||
@@ -491,7 +522,7 @@ func templatesKubernetesTmpl() (*asset, error) {
|
||||
|
||||
var _templatesKvTmpl = []byte(`{{$frontends := List .Prefix "/frontends/" }}
|
||||
{{$backends := List .Prefix "/backends/"}}
|
||||
{{$tlsconfiguration := List .Prefix "/tlsconfiguration/"}}
|
||||
{{$tls := List .Prefix "/tls/"}}
|
||||
|
||||
[backends]{{range $backends}}
|
||||
{{$backend := .}}
|
||||
@@ -511,7 +542,7 @@ var _templatesKvTmpl = []byte(`{{$frontends := List .Prefix "/frontends/" }}
|
||||
sticky = {{ getSticky . }}
|
||||
{{if hasStickinessLabel $backend}}
|
||||
[backends."{{$backendName}}".loadBalancer.stickiness]
|
||||
cookieName = {{getStickinessCookieName $backend}}
|
||||
cookieName = "{{getStickinessCookieName $backend}}"
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
@@ -541,7 +572,7 @@ var _templatesKvTmpl = []byte(`{{$frontends := List .Prefix "/frontends/" }}
|
||||
|
||||
[frontends]{{range $frontends}}
|
||||
{{$frontend := Last .}}
|
||||
{{$entryPoints := SplitGet . "/entrypoints"}}
|
||||
{{$entryPoints := GetList . "/entrypoints"}}
|
||||
[frontends."{{$frontend}}"]
|
||||
backend = "{{Get "" . "/backend"}}"
|
||||
passHostHeader = {{Get "true" . "/passHostHeader"}}
|
||||
@@ -556,13 +587,13 @@ var _templatesKvTmpl = []byte(`{{$frontends := List .Prefix "/frontends/" }}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{range $tlsconfiguration}}
|
||||
{{range $tls}}
|
||||
{{$entryPoints := SplitGet . "/entrypoints"}}
|
||||
[[tlsConfiguration]]
|
||||
[[tls]]
|
||||
entryPoints = [{{range $entryPoints}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
[tlsConfiguration.certificate]
|
||||
[tls.certificate]
|
||||
certFile = """{{Get "" . "/certificate" "/certfile"}}"""
|
||||
keyFile = """{{Get "" . "/certificate" "/keyfile"}}"""
|
||||
{{end}}
|
||||
@@ -752,13 +783,20 @@ var _templatesRancherTmpl = []byte(`{{$backendServers := .Backends}}
|
||||
backend = "backend-{{getBackend $service}}"
|
||||
passHostHeader = {{getPassHostHeader $service}}
|
||||
priority = {{getPriority $service}}
|
||||
redirect = "{{getRedirect $service}}"
|
||||
entryPoints = [{{range getEntryPoints $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
basicAuth = [{{range getBasicAuth $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $service}}
|
||||
[frontends."frontend-{{$frontendName}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $service}}"
|
||||
regex = "{{getRedirectRegex $service}}"
|
||||
replacement = "{{getRedirectReplacement $service}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontendName}}".routes."route-frontend-{{$frontendName}}"]
|
||||
rule = "{{getFrontendRule $service}}"
|
||||
{{end}}
|
||||
|
||||
@@ -4,23 +4,19 @@ RUN apk --update upgrade \
|
||||
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN go get github.com/jteeuwen/go-bindata/... \
|
||||
RUN go get github.com/containous/go-bindata/... \
|
||||
&& go get github.com/golang/lint/golint \
|
||||
&& go get github.com/kisielk/errcheck \
|
||||
&& go get github.com/client9/misspell/cmd/misspell \
|
||||
&& go get github.com/mattfarina/glide-hash \
|
||||
&& go get github.com/sgotti/glide-vc
|
||||
&& go get github.com/client9/misspell/cmd/misspell
|
||||
|
||||
# Which docker version to test on
|
||||
ARG DOCKER_VERSION=17.03.2
|
||||
ARG DEP_VERSION=0.4.1
|
||||
|
||||
# Which glide version to test on
|
||||
ARG GLIDE_VERSION=v0.12.3
|
||||
|
||||
# Download glide
|
||||
# Download dep binary to bin folder in $GOPATH
|
||||
RUN mkdir -p /usr/local/bin \
|
||||
&& curl -fL https://github.com/Masterminds/glide/releases/download/${GLIDE_VERSION}/glide-${GLIDE_VERSION}-linux-amd64.tar.gz \
|
||||
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
||||
&& curl -fsSL -o /usr/local/bin/dep https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 \
|
||||
&& chmod +x /usr/local/bin/dep
|
||||
|
||||
# Download docker
|
||||
RUN mkdir -p /usr/local/bin \
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
Replacement: "foo Replacement",
|
||||
Regex: "foo Regex",
|
||||
EntryPoint: "foo EntryPoint",
|
||||
@@ -103,7 +103,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
Replacement: "fii Replacement",
|
||||
Regex: "fii Regex",
|
||||
EntryPoint: "fii EntryPoint",
|
||||
@@ -168,7 +168,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||
OnHostRule: true,
|
||||
CAServer: "CAServer",
|
||||
EntryPoint: "EntryPoint",
|
||||
DNSProvider: "DNSProvider",
|
||||
DNSChallenge: &acme.DNSChallenge{Provider: "DNSProvider"},
|
||||
DelayDontCheckDNS: 666,
|
||||
ACMELogging: true,
|
||||
TLSConfig: &tls.Config{
|
||||
|
||||
@@ -84,7 +84,7 @@ Add more configuration information here.
|
||||
)
|
||||
|
||||
// newBugCmd builds a new Bug command
|
||||
func newBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration interface{}) *flaeg.Command {
|
||||
func newBugCmd(traefikConfiguration *TraefikConfiguration, traefikPointersConfiguration *TraefikConfiguration) *flaeg.Command {
|
||||
|
||||
//version Command init
|
||||
return &flaeg.Command{
|
||||
@@ -99,7 +99,7 @@ func newBugCmd(traefikConfiguration interface{}, traefikPointersConfiguration in
|
||||
}
|
||||
}
|
||||
|
||||
func runBugCmd(traefikConfiguration interface{}) func() error {
|
||||
func runBugCmd(traefikConfiguration *TraefikConfiguration) func() error {
|
||||
return func() error {
|
||||
|
||||
body, err := createBugReport(traefikConfiguration)
|
||||
@@ -113,7 +113,7 @@ func runBugCmd(traefikConfiguration interface{}) func() error {
|
||||
}
|
||||
}
|
||||
|
||||
func createBugReport(traefikConfiguration interface{}) (string, error) {
|
||||
func createBugReport(traefikConfiguration *TraefikConfiguration) (string, error) {
|
||||
var version bytes.Buffer
|
||||
if err := getVersionPrint(&version); err != nil {
|
||||
return "", err
|
||||
@@ -124,7 +124,7 @@ func createBugReport(traefikConfiguration interface{}) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
config, err := anonymize.Do(&traefikConfiguration, true)
|
||||
config, err := anonymize.Do(traefikConfiguration, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -7,16 +7,27 @@ import (
|
||||
"github.com/containous/traefik/configuration"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_createBugReport(t *testing.T) {
|
||||
traefikConfiguration := TraefikConfiguration{
|
||||
traefikConfiguration := &TraefikConfiguration{
|
||||
ConfigFile: "FOO",
|
||||
GlobalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"goo": &configuration.EntryPoint{
|
||||
Address: "hoo.bar",
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
UsersFile: "foo Basic UsersFile",
|
||||
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
|
||||
},
|
||||
Digest: &types.Digest{
|
||||
UsersFile: "foo Digest UsersFile",
|
||||
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
File: &file.Provider{
|
||||
@@ -28,6 +39,11 @@ func Test_createBugReport(t *testing.T) {
|
||||
|
||||
report, err := createBugReport(traefikConfiguration)
|
||||
assert.NoError(t, err, report)
|
||||
|
||||
// exported anonymous configuration
|
||||
assert.NotContains(t, "web Basic Users ", report)
|
||||
assert.NotContains(t, "foo Digest Users ", report)
|
||||
assert.NotContains(t, "hoo.bar", report)
|
||||
}
|
||||
|
||||
func Test_anonymize_traefikConfiguration(t *testing.T) {
|
||||
|
||||
@@ -61,7 +61,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||
// TODO: Deprecated - default Metrics
|
||||
defaultWeb.Metrics = &types.Metrics{
|
||||
Prometheus: &types.Prometheus{
|
||||
Buckets: types.Buckets{0.1, 0.3, 1.2, 5},
|
||||
Buckets: types.Buckets{0.1, 0.3, 1.2, 5},
|
||||
EntryPoint: configuration.DefaultInternalEntryPointName,
|
||||
},
|
||||
Datadog: &types.Datadog{
|
||||
Address: "localhost:8125",
|
||||
@@ -112,7 +113,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||
var defaultZookeeper zk.Provider
|
||||
defaultZookeeper.Watch = true
|
||||
defaultZookeeper.Endpoint = "127.0.0.1:2181"
|
||||
defaultZookeeper.Prefix = "/traefik"
|
||||
defaultZookeeper.Prefix = "traefik"
|
||||
defaultZookeeper.Constraints = types.Constraints{}
|
||||
|
||||
//default Boltdb
|
||||
@@ -220,7 +221,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||
defaultMetrics := types.Metrics{
|
||||
Prometheus: &types.Prometheus{
|
||||
Buckets: types.Buckets{0.1, 0.3, 1.2, 5},
|
||||
EntryPoint: "traefik",
|
||||
EntryPoint: configuration.DefaultInternalEntryPointName,
|
||||
},
|
||||
Datadog: &types.Datadog{
|
||||
Address: "localhost:8125",
|
||||
@@ -286,6 +287,9 @@ func NewTraefikConfiguration() *TraefikConfiguration {
|
||||
HealthCheck: &configuration.HealthCheckConfig{
|
||||
Interval: flaeg.Duration(configuration.DefaultHealthCheckInterval),
|
||||
},
|
||||
LifeCycle: &configuration.LifeCycle{
|
||||
GraceTimeOut: flaeg.Duration(configuration.DefaultGraceTimeout),
|
||||
},
|
||||
CheckNewVersion: true,
|
||||
},
|
||||
ConfigFile: "",
|
||||
|
||||
@@ -29,11 +29,6 @@ func runHealthCheck(traefikConfiguration *TraefikConfiguration) func() error {
|
||||
return func() error {
|
||||
traefikConfiguration.GlobalConfiguration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
|
||||
|
||||
if traefikConfiguration.Ping == nil {
|
||||
fmt.Println("Please enable `ping` to use healtcheck.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
resp, errPing := healthCheck(traefikConfiguration.GlobalConfiguration)
|
||||
if errPing != nil {
|
||||
fmt.Printf("Error calling healthcheck: %s\n", errPing)
|
||||
@@ -50,9 +45,13 @@ func runHealthCheck(traefikConfiguration *TraefikConfiguration) func() error {
|
||||
}
|
||||
|
||||
func healthCheck(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) {
|
||||
if globalConfiguration.Ping == nil {
|
||||
return nil, errors.New("please enable `ping` to use health check")
|
||||
}
|
||||
|
||||
pingEntryPoint, ok := globalConfiguration.EntryPoints[globalConfiguration.Ping.EntryPoint]
|
||||
if !ok {
|
||||
return nil, errors.New("missing ping entrypoint")
|
||||
return nil, errors.New("missing `ping` entrypoint")
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
|
||||
@@ -67,12 +67,21 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||
return err
|
||||
}
|
||||
}
|
||||
if traefikConfiguration.GlobalConfiguration.ACME != nil && len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
||||
// convert ACME json file to KV store
|
||||
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
||||
object, err := localStore.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
if traefikConfiguration.GlobalConfiguration.ACME != nil {
|
||||
var object cluster.Object
|
||||
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
||||
// convert ACME json file to KV store
|
||||
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
||||
object, err = localStore.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
// Create an empty account to create all the keys into the KV store
|
||||
account := &acme.Account{}
|
||||
account.Init()
|
||||
object = account
|
||||
}
|
||||
|
||||
meta := cluster.NewMetadata(object)
|
||||
@@ -89,6 +98,11 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Force to delete storagefile
|
||||
err = kv.Delete(kv.Prefix + "/acme/storagefile")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/containous/traefik/version"
|
||||
"github.com/coreos/go-systemd/daemon"
|
||||
"github.com/ogier/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -75,6 +76,9 @@ Complete documentation is available at https://traefik.io`,
|
||||
}
|
||||
|
||||
if _, err := f.Parse(usedCmd); err != nil {
|
||||
if err == pflag.ErrHelp {
|
||||
os.Exit(0)
|
||||
}
|
||||
fmtlog.Printf("Error parsing command: %s\n", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
@@ -142,6 +146,7 @@ func run(globalConfiguration *configuration.GlobalConfiguration, configFile stri
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
globalConfiguration.SetEffectiveConfiguration(configFile)
|
||||
globalConfiguration.ValidateConfiguration()
|
||||
|
||||
jsonConf, _ := json.Marshal(globalConfiguration)
|
||||
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
|
||||
@@ -261,14 +266,14 @@ func stats(globalConfiguration *configuration.GlobalConfiguration) {
|
||||
Stats collection is enabled.
|
||||
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
|
||||
Help us improve Traefik by leaving this feature on :)
|
||||
More details on: https://docs.traefik.io/basic/#collected-data
|
||||
More details on: https://docs.traefik.io/basics/#collected-data
|
||||
`)
|
||||
collect(globalConfiguration)
|
||||
} else {
|
||||
log.Info(`
|
||||
Stats collection is disabled.
|
||||
Help us improve Traefik by turning this feature on :)
|
||||
More details on: https://docs.traefik.io/basic/#collected-data
|
||||
More details on: https://docs.traefik.io/basics/#collected-data
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,36 @@ func (gc *GlobalConfiguration) SetEffectiveConfiguration(configFile string) {
|
||||
log.Errorln("Error using file configuration backend, no filename defined")
|
||||
}
|
||||
}
|
||||
|
||||
if gc.ACME != nil {
|
||||
// TODO: to remove in the futurs
|
||||
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
|
||||
}
|
||||
|
||||
if len(gc.ACME.DNSProvider) > 0 {
|
||||
log.Warn("ACME.DNSProvider is deprecated, use ACME.DNSChallenge instead")
|
||||
gc.ACME.DNSChallenge = &acme.DNSChallenge{Provider: gc.ACME.DNSProvider, DelayBeforeCheck: gc.ACME.DelayDontCheckDNS}
|
||||
}
|
||||
|
||||
if gc.ACME.OnDemand {
|
||||
log.Warn("ACME.OnDemand is deprecated")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateConfiguration validate that configuration is coherent
|
||||
func (gc *GlobalConfiguration) ValidateConfiguration() {
|
||||
if gc.ACME != nil {
|
||||
if _, ok := gc.EntryPoints[gc.ACME.EntryPoint]; !ok {
|
||||
log.Fatalf("Unknown entrypoint %q for ACME configuration", gc.ACME.EntryPoint)
|
||||
} else {
|
||||
if gc.EntryPoints[gc.ACME.EntryPoint].TLS == nil {
|
||||
log.Fatalf("Entrypoint without TLS %q for ACME configuration", gc.ACME.EntryPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultEntryPoints holds default entry points
|
||||
@@ -317,9 +347,9 @@ func (ep *EntryPoints) Set(value string) error {
|
||||
Optional: optional,
|
||||
}
|
||||
}
|
||||
var redirect *Redirect
|
||||
var redirect *types.Redirect
|
||||
if len(result["redirect_entrypoint"]) > 0 || len(result["redirect_regex"]) > 0 || len(result["redirect_replacement"]) > 0 {
|
||||
redirect = &Redirect{
|
||||
redirect = &types.Redirect{
|
||||
EntryPoint: result["redirect_entrypoint"],
|
||||
Regex: result["redirect_regex"],
|
||||
Replacement: result["redirect_replacement"],
|
||||
@@ -422,22 +452,15 @@ func (ep *EntryPoints) Type() string {
|
||||
type EntryPoint struct {
|
||||
Network string
|
||||
Address string
|
||||
TLS *tls.TLS `export:"true"`
|
||||
Redirect *Redirect `export:"true"`
|
||||
Auth *types.Auth `export:"true"`
|
||||
TLS *tls.TLS `export:"true"`
|
||||
Redirect *types.Redirect `export:"true"`
|
||||
Auth *types.Auth `export:"true"`
|
||||
WhitelistSourceRange []string
|
||||
Compress bool `export:"true"`
|
||||
ProxyProtocol *ProxyProtocol `export:"true"`
|
||||
ForwardedHeaders *ForwardedHeaders `export:"true"`
|
||||
}
|
||||
|
||||
// Redirect configures a redirection of an entry point to another, or to an URL
|
||||
type Redirect struct {
|
||||
EntryPoint string
|
||||
Regex string
|
||||
Replacement string
|
||||
}
|
||||
|
||||
// Retry contains request retry config
|
||||
type Retry struct {
|
||||
Attempts int `description:"Number of attempts" export:"true"`
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -138,7 +139,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||
expectedEntryPointName: "foo",
|
||||
expectedEntryPoint: &EntryPoint{
|
||||
Address: ":8000",
|
||||
Redirect: &Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "RedirectEntryPoint",
|
||||
Regex: "RedirectRegex",
|
||||
Replacement: "RedirectReplacement",
|
||||
@@ -171,7 +172,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||
expectedEntryPointName: "foo",
|
||||
expectedEntryPoint: &EntryPoint{
|
||||
Address: ":8000",
|
||||
Redirect: &Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "RedirectEntryPoint",
|
||||
Regex: "RedirectRegex",
|
||||
Replacement: "RedirectReplacement",
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
## Current versions documentation
|
||||
|
||||
- [Latest stable](https://docs.traefik.io)
|
||||
|
||||
## Future version documentation
|
||||
|
||||
- [Experimental](https://master--traefik-docs.netlify.com/)
|
||||
|
||||
## Previous versions documentation
|
||||
|
||||
- [v1.5 aka Cancoillotte](http://v1-5.archive.docs.traefik.io/)
|
||||
|
||||
- [v1.4 aka Roquefort](http://v1-4.archive.docs.traefik.io/)
|
||||
|
||||
- [v1.3 aka Raclette](http://v1-3.archive.docs.traefik.io/)
|
||||
|
||||
- [v1.2 aka Morbier](http://v1-2.archive.docs.traefik.io/)
|
||||
|
||||
- [v1.1 aka Camembert](http://v1-1.archive.docs.traefik.io/)
|
||||
|
||||
## More
|
||||
|
||||
[Change log](https://github.com/containous/traefik/blob/master/CHANGELOG.md)
|
||||
@@ -236,7 +236,7 @@ The following rules are both `Matchers` and `Modifiers`, so the `Matcher` portio
|
||||
By default, routes will be sorted (in descending order) using rules length (to avoid path overlap):
|
||||
`PathPrefix:/12345` will be matched before `PathPrefix:/1234` that will be matched before `PathPrefix:/1`.
|
||||
|
||||
You can customize priority by frontend:
|
||||
You can customize priority by frontend. The priority value is added to the rule length during sorting:
|
||||
|
||||
```toml
|
||||
[frontends]
|
||||
@@ -254,7 +254,7 @@ You can customize priority by frontend:
|
||||
rule = "PathPrefix:/toto"
|
||||
```
|
||||
|
||||
Here, `frontend1` will be matched before `frontend2` (`10 > 5`).
|
||||
Here, `frontend1` will be matched before `frontend2` (`(3 + 10 == 13) > (4 + 5 == 9)`).
|
||||
|
||||
#### Custom headers
|
||||
|
||||
@@ -321,42 +321,13 @@ In this example, traffic routed through the first frontend will have the `X-Fram
|
||||
!!! note
|
||||
The detailed documentation for those security headers can be found in [unrolled/secure](https://github.com/unrolled/secure#available-options).
|
||||
|
||||
#### Rate limiting
|
||||
|
||||
Rate limiting can be configured per frontend.
|
||||
Multiple sets of rates can be added to each frontend, but the time periods must be unique.
|
||||
|
||||
```toml
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
passHostHeader = true
|
||||
entrypoints = ["http"]
|
||||
backend = "backend1"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "Path:/"
|
||||
[frontends.frontend1.ratelimit]
|
||||
extractorfunc = "client.ip"
|
||||
[frontends.frontend1.ratelimit.rateset.rateset1]
|
||||
period = "10s"
|
||||
average = 100
|
||||
burst = 200
|
||||
[frontends.frontend1.ratelimit.rateset.rateset2]
|
||||
period = "3s"
|
||||
average = 5
|
||||
burst = 10
|
||||
```
|
||||
|
||||
In the above example, frontend1 is configured to limit requests by the client's ip address.
|
||||
An average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds.
|
||||
These can "burst" up to 10 and 200 in each period respectively.
|
||||
|
||||
### Backends
|
||||
|
||||
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
|
||||
|
||||
Various methods of load-balancing are supported:
|
||||
|
||||
- `wrr`: Weighted Round Robin
|
||||
- `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.
|
||||
|
||||
@@ -373,16 +344,13 @@ It can be configured using:
|
||||
|
||||
For example:
|
||||
|
||||
- `NetworkErrorRatio() > 0.5`: watch error ratio over 10 second sliding window for a frontend
|
||||
- `NetworkErrorRatio() > 0.5`: watch error ratio over 10 second sliding window for a frontend.
|
||||
- `LatencyAtQuantileMS(50.0) > 50`: watch latency at quantile in milliseconds.
|
||||
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`: ratio of response codes in range [500-600) to [0-600)
|
||||
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`: ratio of response codes in ranges [500-600) and [0-600).
|
||||
|
||||
To proactively prevent backends from being overwhelmed with high load, a maximum connection limit can
|
||||
also be applied to each backend.
|
||||
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.
|
||||
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.
|
||||
|
||||
For example:
|
||||
```toml
|
||||
@@ -499,8 +467,8 @@ Here is an example of backends and servers definition:
|
||||
|
||||
Træfik's configuration has two parts:
|
||||
|
||||
- The [static Træfik configuration](/basics#static-trfk-configuration) which is loaded only at the beginning.
|
||||
- The [dynamic Træfik configuration](/basics#dynamic-trfk-configuration) which can be hot-reloaded (no need to restart the process).
|
||||
- The [static Træfik configuration](/basics#static-trfik-configuration) which is loaded only at the beginning.
|
||||
- The [dynamic Træfik configuration](/basics#dynamic-trfik-configuration) which can be hot-reloaded (no need to restart the process).
|
||||
|
||||
### Static Træfik configuration
|
||||
|
||||
@@ -585,7 +553,7 @@ traefik [command] [--flag=flag_argument]
|
||||
List of Træfik available commands with description :
|
||||
|
||||
- `version` : Print version
|
||||
- `storeconfig` : Store the static Traefik configuration into a Key-value stores. Please refer to the [Store Træfik configuration](/user-guide/kv-config/#store-trfk-configuration) section to get documentation on it.
|
||||
- `storeconfig` : Store the static Traefik configuration into a Key-value stores. Please refer to the [Store Træfik configuration](/user-guide/kv-config/#store-configuration-in-key-value-store) section to get documentation on it.
|
||||
- `bug`: The easiest way to submit a pre-filled issue.
|
||||
- `healthcheck`: Calls Traefik `/ping` to check health.
|
||||
|
||||
@@ -601,6 +569,11 @@ Each command is described at the beginning of the help section:
|
||||
|
||||
```bash
|
||||
traefik --help
|
||||
|
||||
# or
|
||||
|
||||
docker run traefik[:version] --help
|
||||
# ex: docker run traefik:1.5 --help
|
||||
```
|
||||
|
||||
### Command: bug
|
||||
@@ -644,6 +617,7 @@ Those data help us prioritize our developments and focus on what's more importan
|
||||
### What ?
|
||||
|
||||
Once a day (the first call begins 10 minutes after the start of Træfik), we collect:
|
||||
|
||||
- the Træfik version
|
||||
- a hash of the configuration
|
||||
- an **anonymous version** of the static configuration:
|
||||
@@ -664,8 +638,7 @@ Once a day (the first call begins 10 minutes after the start of Træfik), we col
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[Docker]
|
||||
endpoint = "tcp://10.10.10.10:2375"
|
||||
@@ -695,8 +668,7 @@ Once a day (the first call begins 10 minutes after the start of Træfik), we col
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[Docker]
|
||||
Endpoint = "xxxx"
|
||||
|
||||
@@ -7,10 +7,14 @@ See also [Let's Encrypt examples](/user-guide/examples/#lets-encrypt-support) an
|
||||
```toml
|
||||
# Sample entrypoint configuration when using ACME.
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
```
|
||||
|
||||
```toml
|
||||
# Enable ACME (Let's Encrypt): automatic SSL.
|
||||
[acme]
|
||||
|
||||
@@ -20,6 +24,12 @@ See also [Let's Encrypt examples](/user-guide/examples/#lets-encrypt-support) an
|
||||
#
|
||||
email = "test@traefik.io"
|
||||
|
||||
# File used for certificates storage.
|
||||
#
|
||||
# Optional (Deprecated)
|
||||
#
|
||||
#storageFile = "acme.json"
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
@@ -27,17 +37,16 @@ email = "test@traefik.io"
|
||||
storage = "acme.json"
|
||||
# or `storage = "traefik/acme/account"` if using KV store.
|
||||
|
||||
# Entrypoint to proxy acme challenge/apply certificates to.
|
||||
# WARNING, must point to an entrypoint on port 443
|
||||
# Entrypoint to proxy acme apply certificates to.
|
||||
# WARNING, if the TLS-SNI-01 challenge is used, it must point to an entrypoint on port 443
|
||||
#
|
||||
# Required
|
||||
#
|
||||
entryPoint = "https"
|
||||
|
||||
# Use a DNS based acme challenge rather than external HTTPS access
|
||||
# Use a DNS-01 acme challenge rather than TLS-SNI-01 challenge
|
||||
#
|
||||
#
|
||||
# Optional
|
||||
# Optional (Deprecated, replaced by [acme.dnsChallenge])
|
||||
#
|
||||
# dnsProvider = "digitalocean"
|
||||
|
||||
@@ -45,25 +54,29 @@ entryPoint = "https"
|
||||
# If delayDontCheckDNS is greater than zero, avoid this & instead just wait so many seconds.
|
||||
# Useful if internal networks block external DNS queries.
|
||||
#
|
||||
# Optional
|
||||
# Optional (Deprecated, replaced by [acme.dnsChallenge])
|
||||
# Default: 0
|
||||
#
|
||||
# delayDontCheckDNS = 0
|
||||
|
||||
# If true, display debug log messages from the acme client library.
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
# acmeLogging = true
|
||||
|
||||
# Enable on demand certificate.
|
||||
# Enable on demand certificate generation.
|
||||
#
|
||||
# Optional
|
||||
# Optional (Deprecated)
|
||||
# Default: false
|
||||
#
|
||||
# onDemand = true
|
||||
|
||||
# Enable certificate generation on frontends Host rules.
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
# onHostRule = true
|
||||
|
||||
@@ -72,23 +85,79 @@ entryPoint = "https"
|
||||
# - Leave comment to go to prod.
|
||||
#
|
||||
# Optional
|
||||
# Default: "https://acme-v01.api.letsencrypt.org/directory"
|
||||
#
|
||||
# caServer = "https://acme-staging.api.letsencrypt.org/directory"
|
||||
|
||||
# Domains list.
|
||||
#
|
||||
# [[acme.domains]]
|
||||
# main = "local1.com"
|
||||
# sans = ["test1.local1.com", "test2.local1.com"]
|
||||
# main = "local1.com"
|
||||
# sans = ["test1.local1.com", "test2.local1.com"]
|
||||
# [[acme.domains]]
|
||||
# main = "local2.com"
|
||||
# sans = ["test1.local2.com", "test2.local2.com"]
|
||||
# main = "local2.com"
|
||||
# sans = ["test1.local2.com", "test2.local2.com"]
|
||||
# [[acme.domains]]
|
||||
# main = "local3.com"
|
||||
# main = "local3.com"
|
||||
# [[acme.domains]]
|
||||
# main = "local4.com"
|
||||
# main = "local4.com"
|
||||
|
||||
# Use a HTTP-01 acme challenge rather than TLS-SNI-01 challenge
|
||||
#
|
||||
# Optional but recommend
|
||||
#
|
||||
[acme.httpChallenge]
|
||||
|
||||
# EntryPoint to use for the challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
entryPoint = "http"
|
||||
|
||||
# Use a DNS-01 acme challenge rather than TLS-SNI-01 challenge
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# [acme.dnsChallenge]
|
||||
|
||||
# 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.
|
||||
# Useful if internal networks block external DNS queries.
|
||||
#
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
# delayBeforeCheck = 0
|
||||
```
|
||||
|
||||
!!! note
|
||||
Even if `TLS-SNI-01` challenge is [disabled](https://community.letsencrypt.org/t/2018-01-11-update-regarding-acme-tls-sni-and-shared-hosting-infrastructure/50188) for the moment, it stays the _by default_ ACME Challenge in Træfik.
|
||||
If `TLS-SNI-01` challenge is not re-enabled in the future, it we will be removed from Træfik.
|
||||
|
||||
!!! note
|
||||
If `TLS-SNI-01` challenge is used, `acme.entryPoint` has to be reachable by Let's Encrypt through the port 443.
|
||||
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).
|
||||
|
||||
### 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`
|
||||
|
||||
```toml
|
||||
@@ -98,9 +167,27 @@ storage = "acme.json"
|
||||
# ...
|
||||
```
|
||||
|
||||
File or key used for certificates storage.
|
||||
The `storage` option sets where are stored your ACME certificates.
|
||||
|
||||
**WARNING** If you use Traefik in Docker, you have 2 options:
|
||||
There are two kind of `storage` :
|
||||
|
||||
- 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
|
||||
@@ -109,7 +196,6 @@ 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"
|
||||
@@ -118,16 +204,80 @@ storage = "/etc/traefik/acme/acme.json"
|
||||
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||
```
|
||||
|
||||
### `dnsProvider`
|
||||
!!! 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.
|
||||
|
||||
```toml
|
||||
storage = "traefik/acme/account"
|
||||
```
|
||||
|
||||
**This kind of storage is mandatory in cluster mode.**
|
||||
|
||||
Because KV stores (like Consul) have limited entries size, the certificates list is compressed before to be set in a KV store entry.
|
||||
|
||||
!!! note
|
||||
It's possible to store up to approximately 100 ACME certificates in Consul.
|
||||
|
||||
### `acme.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.
|
||||
|
||||
```toml
|
||||
[acme]
|
||||
# ...
|
||||
dnsProvider = "digitalocean"
|
||||
entryPoint = "https"
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
```
|
||||
|
||||
#### `entryPoint`
|
||||
|
||||
Specify the entryPoint to use during the challenges.
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http", "http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
# ...
|
||||
|
||||
[acme]
|
||||
# ...
|
||||
entryPoint = "https"
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
```
|
||||
|
||||
!!! 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.dnsChallenge`
|
||||
|
||||
Use `DNS-01` challenge to generate/renew ACME certificates.
|
||||
|
||||
```toml
|
||||
[acme]
|
||||
# ...
|
||||
[acme.dnsChallenge]
|
||||
provider = "digitalocean"
|
||||
delayBeforeCheck = 0
|
||||
# ...
|
||||
```
|
||||
|
||||
Use a DNS based acme challenge rather than external HTTPS access, e.g. for a firewalled server.
|
||||
#### `provider`
|
||||
|
||||
Select the provider that matches the DNS domain that will host the challenge TXT record, and provide environment variables to enable setting it:
|
||||
|
||||
@@ -135,7 +285,7 @@ Select the provider that matches the DNS domain that will host the challenge TXT
|
||||
|--------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| [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` |
|
||||
| [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` |
|
||||
| [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` |
|
||||
@@ -146,7 +296,7 @@ Select the provider that matches the DNS domain that will host the challenge TXT
|
||||
| [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 Traefik interactively & turn on `acmeLogging` to see instructions & press <kbd>Enter</kbd>. |
|
||||
| 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` |
|
||||
@@ -157,21 +307,20 @@ Select the provider that matches the DNS domain that will host the challenge TXT
|
||||
| [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` |
|
||||
|
||||
### `delayDontCheckDNS`
|
||||
#### `delayBeforeCheck`
|
||||
|
||||
```toml
|
||||
[acme]
|
||||
# ...
|
||||
delayDontCheckDNS = 0
|
||||
# ...
|
||||
```
|
||||
|
||||
By default, the dnsProvider will verify the TXT DNS challenge record before letting ACME verify.
|
||||
If `delayDontCheckDNS` 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, avoid this & instead just wait so many seconds.
|
||||
|
||||
Useful if internal networks block external DNS queries.
|
||||
|
||||
### `onDemand`
|
||||
!!! note
|
||||
This field has no sense if a `provider` is not defined.
|
||||
|
||||
### `onDemand` (Deprecated)
|
||||
|
||||
!!! danger "DEPRECATED"
|
||||
This option is deprecated.
|
||||
|
||||
```toml
|
||||
[acme]
|
||||
@@ -182,13 +331,13 @@ onDemand = true
|
||||
|
||||
Enable on demand certificate.
|
||||
|
||||
This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate.
|
||||
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.
|
||||
|
||||
!!! warning
|
||||
TLS handshakes will be slow when requesting a hostname certificate for the first time, this can lead to DoS attacks.
|
||||
|
||||
TLS handshakes will be 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 have [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
||||
|
||||
### `onHostRule`
|
||||
|
||||
@@ -199,7 +348,7 @@ onHostRule = true
|
||||
# ...
|
||||
```
|
||||
|
||||
Enable certificate generation on frontends Host rules.
|
||||
Enable certificate generation on frontends `Host` rules (for frontends wired on the `acme.entryPoint`).
|
||||
|
||||
This will request a certificate from Let's Encrypt for each frontend with a Host rule.
|
||||
|
||||
@@ -219,28 +368,40 @@ CA server to use.
|
||||
- Uncomment the line to run on the staging Let's Encrypt server.
|
||||
- Leave comment to go to prod.
|
||||
|
||||
### `domains`
|
||||
### `acme.domains`
|
||||
|
||||
```toml
|
||||
[acme]
|
||||
# ...
|
||||
[[acme.domains]]
|
||||
main = "local1.com"
|
||||
sans = ["test1.local1.com", "test2.local1.com"]
|
||||
main = "local1.com"
|
||||
sans = ["test1.local1.com", "test2.local1.com"]
|
||||
[[acme.domains]]
|
||||
main = "local2.com"
|
||||
sans = ["test1.local2.com", "test2.local2.com"]
|
||||
main = "local2.com"
|
||||
sans = ["test1.local2.com", "test2.local2.com"]
|
||||
[[acme.domains]]
|
||||
main = "local3.com"
|
||||
main = "local3.com"
|
||||
[[acme.domains]]
|
||||
main = "local4.com"
|
||||
main = "local4.com"
|
||||
# ...
|
||||
```
|
||||
|
||||
You can provide SANs (alternative domains) to each main domain.
|
||||
All domains must have A/AAAA records pointing to Traefik.
|
||||
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.
|
||||
|
||||
### `dnsProvider` (Deprecated)
|
||||
|
||||
!!! danger "DEPRECATED"
|
||||
This option is deprecated.
|
||||
Please refer to [DNS challenge provider section](/configuration/acme/#provider)
|
||||
|
||||
### `delayDontCheckDNS` (Deprecated)
|
||||
|
||||
!!! danger "DEPRECATED"
|
||||
This option is deprecated.
|
||||
Please refer to [DNS challenge delayBeforeCheck section](/configuration/acme/#delaybeforecheck)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# API Definition
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml
|
||||
# API definition
|
||||
[api]
|
||||
@@ -28,6 +30,8 @@
|
||||
debug = true
|
||||
```
|
||||
|
||||
For more customization, see [entry points](/configuration/entrypoints/) documentation and [examples](/user-guide/examples/#ping-health-check).
|
||||
|
||||
## Web UI
|
||||
|
||||

|
||||
@@ -42,7 +46,7 @@
|
||||
| `/health` | `GET` | json health metrics |
|
||||
| `/api` | `GET` | Configuration for all providers |
|
||||
| `/api/providers` | `GET` | Providers |
|
||||
| `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider |
|
||||
| `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider (1) |
|
||||
| `/api/providers/{provider}/backends` | `GET` | List backends |
|
||||
| `/api/providers/{provider}/backends/{backend}` | `GET` | Get backend |
|
||||
| `/api/providers/{provider}/backends/{backend}/servers` | `GET` | List servers in backend |
|
||||
@@ -52,6 +56,8 @@
|
||||
| `/api/providers/{provider}/frontends/{frontend}/routes` | `GET` | List routes in a frontend |
|
||||
| `/api/providers/{provider}/frontends/{frontend}/routes/{route}` | `GET` | Get a route in a frontend |
|
||||
|
||||
<1> See [Rest](/configuration/backends/rest/#api) for more information.
|
||||
|
||||
!!! warning
|
||||
For compatibility reason, when you activate the rest provider, you can use `web` or `rest` as `provider` value.
|
||||
But be careful, in the configuration for all providers the key is still `web`.
|
||||
@@ -161,7 +167,7 @@ curl -s "http://localhost:8080/health" | jq .
|
||||
// average response time in seconds
|
||||
"average_response_time_sec": 0.8648016000000001,
|
||||
|
||||
// request statistics [requires --web.statistics to be set]
|
||||
// request statistics [requires --statistics to be set]
|
||||
// ten most recent requests with 4xx and 5xx status codes
|
||||
"recent_errors": [
|
||||
{
|
||||
@@ -185,6 +191,7 @@ curl -s "http://localhost:8080/health" | jq .
|
||||
## Metrics
|
||||
|
||||
You can enable Traefik to export internal metrics to different monitoring systems.
|
||||
|
||||
```toml
|
||||
[api]
|
||||
# ...
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Consul Backend
|
||||
|
||||
## Consul Key-Value backend
|
||||
# Consul Key-Value backend
|
||||
|
||||
Træfik can be configured to use Consul as a backend configuration.
|
||||
|
||||
@@ -61,91 +59,3 @@ prefix = "traefik"
|
||||
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-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.
|
||||
|
||||
## Consul Catalog backend
|
||||
|
||||
Træfik can be configured to use service discovery catalog of Consul as a backend configuration.
|
||||
|
||||
```toml
|
||||
################################################################
|
||||
# Consul Catalog configuration backend
|
||||
################################################################
|
||||
|
||||
# Enable Consul Catalog configuration backend.
|
||||
[consulCatalog]
|
||||
|
||||
# Consul server endpoint.
|
||||
#
|
||||
# Required
|
||||
# Default: "127.0.0.1:8500"
|
||||
#
|
||||
endpoint = "127.0.0.1:8500"
|
||||
|
||||
# Expose Consul catalog services by default in Traefik.
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
exposedByDefault = false
|
||||
|
||||
# Prefix for Consul catalog tags.
|
||||
#
|
||||
# Optional
|
||||
# Default: "traefik"
|
||||
#
|
||||
prefix = "traefik"
|
||||
|
||||
# Default frontEnd Rule for Consul services.
|
||||
#
|
||||
# The format is a Go Template with:
|
||||
# - ".ServiceName", ".Domain" and ".Attributes" available
|
||||
# - "getTag(name, tags, defaultValue)", "hasTag(name, tags)" and "getAttribute(name, tags, defaultValue)" functions are available
|
||||
# - "getAttribute(...)" function uses prefixed tag names based on "prefix" value
|
||||
#
|
||||
# Optional
|
||||
# Default: "Host:{{.ServiceName}}.{{.Domain}}"
|
||||
#
|
||||
#frontEndRule = "Host:{{.ServiceName}}.{{Domain}}"
|
||||
```
|
||||
|
||||
This backend 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).
|
||||
|
||||
### Tags
|
||||
|
||||
Additional settings can be defined using Consul Catalog tags.
|
||||
|
||||
| Tag | Description |
|
||||
|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.backend.weight=10` | Assign this weight to the container |
|
||||
| `traefik.backend.circuitbreaker=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend, ex: `NetworkErrorRatio() > 0.` |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. 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. Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{{.ServiceName}}.{{.Domain}}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.backend.loadbalancer=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) |
|
||||
|
||||
### Examples
|
||||
|
||||
If you want that Træfik uses Consul tags correctly you need to defined them like that:
|
||||
```json
|
||||
traefik.enable=true
|
||||
traefik.tags=api
|
||||
traefik.tags=external
|
||||
```
|
||||
|
||||
If the prefix defined in Træfik configuration is `bla`, tags need to be defined like that:
|
||||
```json
|
||||
bla.enable=true
|
||||
bla.tags=api
|
||||
bla.tags=external
|
||||
```
|
||||
93
docs/configuration/backends/consulcatalog.md
Normal file
93
docs/configuration/backends/consulcatalog.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Consul Catalog backend
|
||||
|
||||
Træfik can be configured to use service discovery catalog of Consul as a backend configuration.
|
||||
|
||||
```toml
|
||||
################################################################
|
||||
# Consul Catalog configuration backend
|
||||
################################################################
|
||||
|
||||
# Enable Consul Catalog configuration backend.
|
||||
[consulCatalog]
|
||||
|
||||
# Consul server endpoint.
|
||||
#
|
||||
# Required
|
||||
# Default: "127.0.0.1:8500"
|
||||
#
|
||||
endpoint = "127.0.0.1:8500"
|
||||
|
||||
# Expose Consul catalog services by default in Traefik.
|
||||
#
|
||||
# Optional
|
||||
# Default: true
|
||||
#
|
||||
exposedByDefault = false
|
||||
|
||||
# Default domain used.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
domain = "consul.localhost"
|
||||
|
||||
# Prefix for Consul catalog tags.
|
||||
#
|
||||
# Optional
|
||||
# Default: "traefik"
|
||||
#
|
||||
prefix = "traefik"
|
||||
|
||||
# Default frontEnd Rule for Consul services.
|
||||
#
|
||||
# The format is a Go Template with:
|
||||
# - ".ServiceName", ".Domain" and ".Attributes" available
|
||||
# - "getTag(name, tags, defaultValue)", "hasTag(name, tags)" and "getAttribute(name, tags, defaultValue)" functions are available
|
||||
# - "getAttribute(...)" function uses prefixed tag names based on "prefix" value
|
||||
#
|
||||
# Optional
|
||||
# Default: "Host:{{.ServiceName}}.{{.Domain}}"
|
||||
#
|
||||
#frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
||||
```
|
||||
|
||||
This backend 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).
|
||||
|
||||
### Tags
|
||||
|
||||
Additional settings can be defined using Consul Catalog tags.
|
||||
|
||||
| Tag | Description |
|
||||
|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.backend.weight=10` | Assign this weight to the container |
|
||||
| `traefik.backend.circuitbreaker=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend, ex: `NetworkErrorRatio() > 0.` |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. 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. Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{{.ServiceName}}.{{.Domain}}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.backend.loadbalancer=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) |
|
||||
|
||||
### Examples
|
||||
|
||||
If you want that Træfik uses Consul tags correctly you need to defined them like that:
|
||||
```json
|
||||
traefik.enable=true
|
||||
traefik.tags=api
|
||||
traefik.tags=external
|
||||
```
|
||||
|
||||
If the prefix defined in Træfik configuration is `bla`, tags need to be defined like that:
|
||||
```json
|
||||
bla.enable=true
|
||||
bla.tags=api
|
||||
bla.tags=external
|
||||
```
|
||||
@@ -145,33 +145,51 @@ To enable constraints see [backend-specific constraints section](/configuration/
|
||||
|
||||
## Labels: overriding default behaviour
|
||||
|
||||
!!! note
|
||||
If you use a compose file, labels should be defined in the `deploy` part of your service.
|
||||
|
||||
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/#labels-1)).
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
whoami:
|
||||
deploy:
|
||||
labels:
|
||||
traefik.docker.network: traefik
|
||||
```
|
||||
|
||||
### On Containers
|
||||
|
||||
Labels can be used on containers to override default behaviour.
|
||||
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. 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. Must be used in conjunction with the above label to take effect. |
|
||||
| `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.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `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.enable=false` | Disable this container in Træfik |
|
||||
| `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.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. 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.docker.network` | Set the docker network to use for connections to this container. 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. |
|
||||
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| Label | Description |
|
||||
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. 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. Must be used in conjunction with the above label to take effect. |
|
||||
| `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.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `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.enable=false` | Disable this container in Træfik |
|
||||
| `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.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. 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.docker.network` | Set the docker network to use for connections to this container. 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. |
|
||||
| `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. Must be set with `traefik.frontend.redirect.replacement`. |
|
||||
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.regex`. |
|
||||
|
||||
|
||||
|
||||
#### Security Headers
|
||||
|
||||
@@ -202,26 +220,31 @@ Labels can be used on containers to override default behaviour.
|
||||
|
||||
Services labels can be used for overriding default behaviour
|
||||
|
||||
| Label | Description |
|
||||
|---------------------------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `traefik.<service-name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the service labels could be used. |
|
||||
| `traefik.<service-name>.protocol` | Overrides `traefik.protocol`. |
|
||||
| `traefik.<service-name>.weight` | Assign this service weight. Overrides `traefik.weight`. |
|
||||
| `traefik.<service-name>.frontend.backend=BACKEND` | Assign this service frontend to `BACKEND`. Default is to assign to the service backend. |
|
||||
| `traefik.<service-name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
|
||||
| `traefik.<service-name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
|
||||
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
||||
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
||||
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
||||
| `traefik.<service-name>.frontend.redirect` | Overrides `traefik.frontend.redirect`. |
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `traefik.<service-name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the service labels could be used. |
|
||||
| `traefik.<service-name>.protocol` | Overrides `traefik.protocol`. |
|
||||
| `traefik.<service-name>.weight` | Assign this service weight. Overrides `traefik.weight`. |
|
||||
| `traefik.<service-name>.frontend.backend=BACKEND` | Assign this service frontend to `BACKEND`. Default is to assign to the service backend. |
|
||||
| `traefik.<service-name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
|
||||
| `traefik.<service-name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
|
||||
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
||||
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
||||
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
||||
| `traefik.<service-name>.frontend.redirect` | Overrides `traefik.frontend.redirect`. |
|
||||
| `traefik.<service-name>.frontend.redirect.entryPoint=https` | Overrides `traefik.frontend.redirect.entryPoint`. |
|
||||
| `traefik.<service-name>.frontend.redirect.regex=^http://localhost/(.*)` | Overrides `traefik.frontend.redirect.regex`. |
|
||||
| `traefik.<service-name>.frontend.redirect.replacement=http://mydomain/$1` | Overrides `traefik.frontend.redirect.replacement`. |
|
||||
|
||||
|
||||
!!! note
|
||||
if a label is defined both as a `container label` and a `service label` (for example `traefik.<service-name>.port=PORT` and `traefik.port=PORT` ), the `service label` is used to defined the `<service-name>` property (`port` in the example).
|
||||
If a label is defined both as a `container label` and a `service label` (for example `traefik.<service-name>.port=PORT` and `traefik.port=PORT` ), the `service label` is used to defined the `<service-name>` property (`port` in the example).
|
||||
|
||||
It's possible to mix `container labels` and `service labels`, in this case `container labels` are used as default value for missing `service labels` but no frontends are going to be created with the `container labels`.
|
||||
|
||||
More details in this [example](/user-guide/docker-and-lets-encrypt/#labels).
|
||||
|
||||
!!! warning
|
||||
when running inside a container, Træfik will need network access through:
|
||||
When running inside a container, Træfik will need network access through:
|
||||
|
||||
`docker network connect <network> <traefik-container>`
|
||||
|
||||
@@ -1,6 +1,140 @@
|
||||
# File Backends
|
||||
|
||||
Like any other reverse proxy, Træfik can be configured with a file.
|
||||
Træfik can be configured with a file.
|
||||
|
||||
## Reference
|
||||
|
||||
```toml
|
||||
# Backends
|
||||
[backends]
|
||||
|
||||
[backends.backend1]
|
||||
|
||||
[backends.backend1.servers]
|
||||
[backends.backend1.servers.server0]
|
||||
url = "http://10.10.10.1:80"
|
||||
weight = 1
|
||||
[backends.backend1.servers.server1]
|
||||
url = "http://10.10.10.2:80"
|
||||
weight = 2
|
||||
# ...
|
||||
|
||||
[backends.backend1.circuitBreaker]
|
||||
expression = "NetworkErrorRatio() > 0.5"
|
||||
|
||||
[backends.backend1.loadBalancer]
|
||||
method = "drr"
|
||||
[backends.backend1.loadBalancer.stickiness]
|
||||
cookieName = "foobar"
|
||||
|
||||
[backends.backend1.maxConn]
|
||||
amount = 10
|
||||
extractorfunc = "request.host"
|
||||
|
||||
[backends.backend1.healthCheck]
|
||||
path = "/health"
|
||||
port = 88
|
||||
interval = "30s"
|
||||
|
||||
[backends.backend2]
|
||||
# ...
|
||||
|
||||
# Frontends
|
||||
[frontends]
|
||||
|
||||
[frontends.frontend1]
|
||||
entryPoints = ["http", "https"]
|
||||
backend = "backend1"
|
||||
passHostHeader = true
|
||||
passTLSCert = true
|
||||
priority = 42
|
||||
basicAuth = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
whitelistSourceRange = ["10.42.0.0/16", "152.89.1.33/32", "afed:be44::/16"]
|
||||
|
||||
[frontends.frontend1.routes]
|
||||
[frontends.frontend1.routes.route0]
|
||||
rule = "Host:test.localhost"
|
||||
[frontends.frontend1.routes.Route1]
|
||||
rule = "Method:GET"
|
||||
# ...
|
||||
|
||||
[frontends.frontend1.headers]
|
||||
allowedHosts = ["foobar", "foobar"]
|
||||
hostsProxyHeaders = ["foobar", "foobar"]
|
||||
SSLRedirect = true
|
||||
SSLTemporaryRedirect = true
|
||||
SSLHost = "foobar"
|
||||
STSSeconds = 42
|
||||
STSIncludeSubdomains = true
|
||||
STSPreload = true
|
||||
forceSTSHeader = true
|
||||
frameDeny = true
|
||||
customFrameOptionsValue = "foobar"
|
||||
contentTypeNosniff = true
|
||||
browserXSSFilter = true
|
||||
contentSecurityPolicy = "foobar"
|
||||
publicKey = "foobar"
|
||||
referrerPolicy = "foobar"
|
||||
isDevelopment = true
|
||||
[frontends.frontend1.headers.customRequestHeaders]
|
||||
X-Foo-Bar-01 = "foobar"
|
||||
X-Foo-Bar-02 = "foobar"
|
||||
# ...
|
||||
[frontends.frontend1.headers.customResponseHeaders]
|
||||
X-Foo-Bar-03 = "foobar"
|
||||
X-Foo-Bar-04 = "foobar"
|
||||
# ...
|
||||
[frontends.frontend1.headers.SSLProxyHeaders]
|
||||
X-Foo-Bar-05 = "foobar"
|
||||
X-Foo-Bar-06 = "foobar"
|
||||
# ...
|
||||
|
||||
[frontends.frontend1.errors]
|
||||
[frontends.frontend1.errors.errorPage0]
|
||||
status = ["500-599"]
|
||||
backend = "error"
|
||||
query = "/{status}.html"
|
||||
[frontends.frontend1.errors.errorPage1]
|
||||
status = ["404", "403"]
|
||||
backend = "error"
|
||||
query = "/{status}.html"
|
||||
# ...
|
||||
|
||||
[frontends.frontend1.ratelimit]
|
||||
extractorfunc = "client.ip"
|
||||
[frontends.frontend1.ratelimit.rateset.rateset1]
|
||||
period = "10s"
|
||||
average = 100
|
||||
burst = 200
|
||||
[frontends.frontend1.ratelimit.rateset.rateset2]
|
||||
period = "3s"
|
||||
average = 5
|
||||
burst = 10
|
||||
# ...
|
||||
|
||||
[frontends.frontend1.redirect]
|
||||
entryPoint = "https"
|
||||
regex = "^http://localhost/(.*)"
|
||||
replacement = "http://mydomain/$1"
|
||||
|
||||
[frontends.frontend2]
|
||||
# ...
|
||||
|
||||
# HTTPS certificates
|
||||
[[tls]]
|
||||
entryPoints = ["https"]
|
||||
[tls.certificate]
|
||||
certFile = "path/to/my.cert"
|
||||
keyFile = "path/to/my.key"
|
||||
|
||||
[[tls]]
|
||||
# ...
|
||||
```
|
||||
|
||||
## Configuration mode
|
||||
|
||||
You have three choices:
|
||||
|
||||
@@ -12,7 +146,7 @@ To enable the file backend, you must either pass the `--file` option to the Træ
|
||||
|
||||
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
|
||||
### Simple
|
||||
|
||||
Add your configuration at the end of the global configuration file `traefik.toml`:
|
||||
|
||||
@@ -21,167 +155,93 @@ defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.redirect]
|
||||
entryPoint = "https"
|
||||
# ...
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
[[entryPoints.https.tls.certificates]]
|
||||
certFile = "integration/fixtures/https/snitest.org.cert"
|
||||
keyFile = "integration/fixtures/https/snitest.org.key"
|
||||
# ...
|
||||
|
||||
[file]
|
||||
|
||||
# rules
|
||||
[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.maxconn]
|
||||
amount = 10
|
||||
extractorfunc = "request.host"
|
||||
[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
|
||||
# ...
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
backend = "backend2"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "Host:test.localhost"
|
||||
|
||||
# ...
|
||||
[frontends.frontend2]
|
||||
backend = "backend1"
|
||||
passHostHeader = true
|
||||
priority = 10
|
||||
|
||||
# restrict access to this frontend to the specified list of IPv4/IPv6 CIDR Nets
|
||||
# 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.
|
||||
whitelistSourceRange = ["10.42.0.0/16", "152.89.1.33/32", "afed:be44::/16"]
|
||||
|
||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||
[frontends.frontend2.routes.test_1]
|
||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||
|
||||
# ...
|
||||
[frontends.frontend3]
|
||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||
backend = "backend2"
|
||||
rule = "Path:/test"
|
||||
# ...
|
||||
|
||||
# HTTPS certificate
|
||||
[[tlsConfiguration]]
|
||||
entryPoints = ["https"]
|
||||
[tlsConfiguration.certificate]
|
||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
||||
[[tls]]
|
||||
# ...
|
||||
|
||||
[[tls]]
|
||||
# ...
|
||||
```
|
||||
|
||||
!!! note
|
||||
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
|
||||
### Rules in a Separate File
|
||||
|
||||
Put your rules in a separate file, for example `rules.toml`:
|
||||
|
||||
```toml
|
||||
# traefik.toml
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.redirect]
|
||||
entryPoint = "https"
|
||||
# ...
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
# ...
|
||||
|
||||
[file]
|
||||
filename = "rules.toml"
|
||||
filename = "rules.toml"
|
||||
```
|
||||
|
||||
```toml
|
||||
# rules.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.maxconn]
|
||||
amount = 10
|
||||
extractorfunc = "request.host"
|
||||
[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
|
||||
# ...
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
backend = "backend2"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "Host:test.localhost"
|
||||
# ...
|
||||
[frontends.frontend2]
|
||||
backend = "backend1"
|
||||
passHostHeader = true
|
||||
priority = 10
|
||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||
[frontends.frontend2.routes.test_1]
|
||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||
# ...
|
||||
[frontends.frontend3]
|
||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||
backend = "backend2"
|
||||
rule = "Path:/test"
|
||||
|
||||
# HTTPS certificate
|
||||
[[tlsConfiguration]]
|
||||
entryPoints = ["https"]
|
||||
[tlsConfiguration.certificate]
|
||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
||||
# ...
|
||||
|
||||
[[tlsConfiguration]]
|
||||
entryPoints = ["https"]
|
||||
[[tlsConfiguration.certificates]]
|
||||
certFile = "integration/fixtures/https/snitest.org.cert"
|
||||
keyFile = "integration/fixtures/https/snitest.org.key"
|
||||
# HTTPS certificate
|
||||
[[tls]]
|
||||
# ...
|
||||
|
||||
[[tls]]
|
||||
# ...
|
||||
```
|
||||
|
||||
## Multiple `.toml` Files
|
||||
### Multiple `.toml` Files
|
||||
|
||||
You could have multiple `.toml` files in a directory (and recursively in its sub-directories):
|
||||
|
||||
```toml
|
||||
[file]
|
||||
directory = "/path/to/config/"
|
||||
directory = "/path/to/config/"
|
||||
```
|
||||
|
||||
If you want Træfik to watch file changes automatically, just add:
|
||||
|
||||
```toml
|
||||
[file]
|
||||
watch = true
|
||||
watch = true
|
||||
```
|
||||
|
||||
@@ -4,7 +4,6 @@ Træfik can be configured to use Kubernetes Ingress as a backend configuration.
|
||||
|
||||
See also [Kubernetes user guide](/user-guide/kubernetes).
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml
|
||||
@@ -44,7 +43,7 @@ See also [Kubernetes user guide](/user-guide/kubernetes).
|
||||
#
|
||||
# namespaces = ["default", "production"]
|
||||
|
||||
# Ingress label selector to identify Ingress objects that should be processed.
|
||||
# Ingress label selector to filter Ingress objects that should be processed.
|
||||
#
|
||||
# Optional
|
||||
# Default: empty (process all Ingresses)
|
||||
@@ -75,79 +74,83 @@ See also [Kubernetes user guide](/user-guide/kubernetes).
|
||||
|
||||
### `endpoint`
|
||||
|
||||
The Kubernetes server endpoint.
|
||||
The Kubernetes server endpoint as URL.
|
||||
|
||||
When deployed as a replication controller in Kubernetes, Traefik will use the environment variables `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` to construct the endpoint.
|
||||
When deployed into Kubernetes, Traefik will read the environment variables `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` to construct the endpoint.
|
||||
|
||||
Secure token will be found in `/var/run/secrets/kubernetes.io/serviceaccount/token` and SSL CA cert in `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`
|
||||
The access token will be looked up in `/var/run/secrets/kubernetes.io/serviceaccount/token` and the SSL CA certificate in `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`.
|
||||
Both are provided mounted automatically when deployed inside Kubernetes.
|
||||
|
||||
The endpoint may be given to override the environment variable values.
|
||||
The endpoint may be specified to override the environment variable values inside a cluster.
|
||||
|
||||
When the environment variables are not found, Traefik will try to connect to the Kubernetes API server with an external-cluster client.
|
||||
In this case, the endpoint is required.
|
||||
Specifically, it may be set to the URL used by `kubectl proxy` to connect to a Kubernetes cluster from localhost.
|
||||
Specifically, it may be set to the URL used by `kubectl proxy` to connect to a Kubernetes cluster using the granted autentication and authorization of the associated kubeconfig.
|
||||
|
||||
### `labelselector`
|
||||
|
||||
Ingress label selector to identify Ingress objects that should be processed.
|
||||
By default, Traefik processes all Ingress objects in the configured namespaces.
|
||||
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.
|
||||
|
||||
|
||||
## Annotations
|
||||
|
||||
Annotations can be used on containers to override default behaviour for the whole Ingress resource:
|
||||
### General annotations
|
||||
|
||||
- `traefik.frontend.rule.type: PathPrefixStrip`
|
||||
The following general annotations are applicable on the Ingress object:
|
||||
|
||||
- `traefik.frontend.rule.type: PathPrefixStrip`
|
||||
Override the default frontend rule type. Default: `PathPrefix`.
|
||||
- `traefik.frontend.priority: "3"`
|
||||
Override the default frontend rule priority.
|
||||
- `traefik.frontend.redirect: https`:
|
||||
- `traefik.frontend.redirect.entryPoint: https`:
|
||||
Enables Redirect to another entryPoint for that frontend (e.g. HTTPS).
|
||||
- `traefik.frontend.entryPoints: http,https`
|
||||
- `traefik.frontend.redirect.regex: ^http://localhost/(.*)`:
|
||||
Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.replacement`.
|
||||
- `traefik.frontend.redirect.replacement: http://mydomain/$1`:
|
||||
Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.regex`.
|
||||
- `traefik.frontend.entryPoints: http,https`
|
||||
Override the default frontend endpoints.
|
||||
- `traefik.frontend.passTLSCert: true`
|
||||
- `traefik.frontend.passTLSCert: true`
|
||||
Override the default frontend PassTLSCert value. Default: `false`.
|
||||
|
||||
Annotations can be used on the Kubernetes service to override default behaviour:
|
||||
|
||||
- `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)
|
||||
|
||||
Additionally, an annotation can be used on Kubernetes services to set the [circuit breaker expression](/basics/#backends) for a backend.
|
||||
|
||||
- `traefik.backend.circuitbreaker: <expression>`
|
||||
Set the circuit breaker expression for the backend. Default: `nil`.
|
||||
|
||||
As known from nginx when used as Kubernetes Ingress Controller, a list of IP-Ranges which are allowed to access can be configured by using an ingress annotation:
|
||||
|
||||
- `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.
|
||||
- `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.
|
||||
|
||||
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.
|
||||
!!! note
|
||||
Please note that `traefik.frontend.redirect.regex` and `traefik.frontend.redirect.replacement` do not have to be set if `traefik.frontend.redirect.entryPoint` is defined for the redirection (they will not be used in this case).
|
||||
|
||||
#### Security annotations
|
||||
The following annotations are applicable on the Service object associated with a particular Ingress object:
|
||||
|
||||
The following security annotations can be applied to the ingress object to add security features:
|
||||
- `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.circuitbreaker: <expression>`
|
||||
Set the circuit breaker expression for the backend.
|
||||
|
||||
| Annotation | Description |
|
||||
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
### Security annotations
|
||||
|
||||
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/custom-request-headers:EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||
| `ingress.kubernetes.io/custom-request-headers:EXPR` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||
| `ingress.kubernetes.io/custom-response-headers:EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||
| `ingress.kubernetes.io/proxy-headers:EXPR ` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
|
||||
| `ingress.kubernetes.io/proxy-headers:EXPR` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` |
|
||||
| `ingress.kubernetes.io/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||HEADER2:value2</code> |
|
||||
| `ingress.kubernetes.io/hsts-max-age:315360000` | Sets the max-age of the HSTS header. |
|
||||
| `ngress.kubernetes.io/hsts-include-subdomains:true` | Adds the IncludeSubdomains section of the STS 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`. |
|
||||
@@ -161,17 +164,17 @@ The following security annotations can be applied to the ingress object to add s
|
||||
|
||||
### Authentication
|
||||
|
||||
Is possible to add additional authentication annotations in the Ingress rule.
|
||||
The source of the authentication is a secret that contains usernames and passwords inside the key auth.
|
||||
Is possible to add additional authentication annotations to the Ingress object.
|
||||
The source of the authentication is a Secret object that contains the credentials.
|
||||
|
||||
- `ingress.kubernetes.io/auth-type`: `basic`
|
||||
- `ingress.kubernetes.io/auth-secret`: `mysecret`
|
||||
Contains the usernames and passwords with access to the paths defined in the Ingress Rule.
|
||||
Contains the authentication type. The only permitted type is `basic`.
|
||||
- `ingress.kubernetes.io/auth-secret`: `mysecret`
|
||||
Contains the username and password with access to the paths defined in the Ingress object.
|
||||
|
||||
The secret must be created in the same namespace as the Ingress rule.
|
||||
The secret must be created in the same namespace as the Ingress object.
|
||||
|
||||
Limitations:
|
||||
The following limitations hold:
|
||||
|
||||
- Basic authentication only.
|
||||
- Realm not configurable; only `traefik` default.
|
||||
- Secret must contain only single file.
|
||||
- The realm is not configurable; the only supported (and default) value is `traefik`.
|
||||
- The Secret must contain a single file only.
|
||||
|
||||
@@ -150,12 +150,15 @@ domain = "marathon.localhost"
|
||||
|
||||
To enable constraints see [backend-specific constraints section](/configuration/commons/#backend-specific).
|
||||
|
||||
|
||||
## Labels: overriding default behaviour
|
||||
|
||||
### On Containers
|
||||
Marathon labels may be used to dynamically change the routing and forwarding behaviour.
|
||||
|
||||
Labels can be used on containers to override default behaviour:
|
||||
They may be specified on one of two levels: Application or service.
|
||||
|
||||
### Application Level
|
||||
|
||||
The following labels can be defined on Marathon applications. They adjust the behaviour for the entire application.
|
||||
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
@@ -180,9 +183,9 @@ Labels can be used on containers to override default behaviour:
|
||||
| `traefik.frontend.entryPoints=http,https` | assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
|
||||
### On Services
|
||||
### Service Level
|
||||
|
||||
If several ports need to be exposed from a container, the services labels can be used:
|
||||
For applications that expose multiple ports, specific labels can be used to extract one frontend/backend configuration pair per port. Each such pair is called a _service_. The (freely choosable) name of the service is an integral part of the service label name.
|
||||
|
||||
| Label | Description |
|
||||
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------|
|
||||
|
||||
@@ -120,19 +120,21 @@ secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
Labels can be used on task containers to override default behaviour:
|
||||
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{containerName}.{domain}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `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) |
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{containerName}.{domain}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `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.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `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) |
|
||||
@@ -35,6 +35,14 @@ address = ":8080"
|
||||
# Default: false
|
||||
#
|
||||
readOnly = true
|
||||
|
||||
# Set the root path for webui and API
|
||||
#
|
||||
# Deprecated
|
||||
# Optional
|
||||
#
|
||||
# path = "/mypath"
|
||||
#
|
||||
```
|
||||
|
||||
## Web UI
|
||||
@@ -46,13 +54,13 @@ readOnly = true
|
||||
### Authentication
|
||||
|
||||
!!! note
|
||||
The `/ping` path of the api is excluded from authentication (since 1.4).
|
||||
The `/ping` path of the API is excluded from authentication (since 1.4).
|
||||
|
||||
#### Basic Authentication
|
||||
|
||||
Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate those ones.
|
||||
|
||||
Users can be specified directly in the toml file, or indirectly by referencing an external file;
|
||||
Users can be specified directly in the TOML file, or indirectly by referencing an external file;
|
||||
if both are provided, the two are merged, with external file contents having precedence.
|
||||
|
||||
```toml
|
||||
@@ -71,7 +79,7 @@ usersFile = "/path/to/.htpasswd"
|
||||
|
||||
You can use `htdigest` to generate those ones.
|
||||
|
||||
Users can be specified directly in the toml file, or indirectly by referencing an external file;
|
||||
Users can be specified directly in the TOML file, or indirectly by referencing an external file;
|
||||
if both are provided, the two are merged, with external file contents having precedence
|
||||
|
||||
```toml
|
||||
@@ -80,7 +88,7 @@ Users can be specified directly in the toml file, or indirectly by referencing a
|
||||
|
||||
# To enable digest auth on the webui with 2 user/realm/pass: test:traefik:test and test2:traefik:test2
|
||||
[web.auth.digest]
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
usersFile = "/path/to/.htdigest"
|
||||
|
||||
# ...
|
||||
@@ -89,7 +97,7 @@ usersFile = "/path/to/.htdigest"
|
||||
|
||||
## Metrics
|
||||
|
||||
You can enable Traefik to export internal metrics to different monitoring systems.
|
||||
You can enable Træfik to export internal metrics to different monitoring systems.
|
||||
|
||||
### Prometheus
|
||||
|
||||
@@ -105,7 +113,7 @@ You can enable Traefik to export internal metrics to different monitoring system
|
||||
# Optional
|
||||
# Default: [0.1, 0.3, 1.2, 5]
|
||||
buckets=[0.1,0.3,1.2,5.0]
|
||||
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -212,7 +220,7 @@ recentErrors = 10
|
||||
|-----------------------------------------------------------------|:-------------:|----------------------------------------------------------------------------------------------------|
|
||||
| `/` | `GET` | Provides a simple HTML frontend of Træfik |
|
||||
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Træfik process liveness. Return a code `200` with the content: `OK` |
|
||||
| `/health` | `GET` | json health metrics |
|
||||
| `/health` | `GET` | JSON health metrics |
|
||||
| `/api` | `GET` | Configuration for all providers |
|
||||
| `/api/providers` | `GET` | Providers |
|
||||
| `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider |
|
||||
@@ -235,7 +243,7 @@ curl -sv "http://localhost:8080/ping"
|
||||
```
|
||||
```shell
|
||||
* Trying ::1...
|
||||
* Connected to localhost (::1) port 8080 (#0)
|
||||
* Connected to localhost (::1) port 8080 (\#0)
|
||||
> GET /ping HTTP/1.1
|
||||
> Host: localhost:8080
|
||||
> User-Agent: curl/7.43.0
|
||||
@@ -246,7 +254,7 @@ curl -sv "http://localhost:8080/ping"
|
||||
< Content-Length: 2
|
||||
< Content-Type: text/plain; charset=utf-8
|
||||
<
|
||||
* Connection #0 to host localhost left intact
|
||||
* Connection \#0 to host localhost left intact
|
||||
OK
|
||||
```
|
||||
|
||||
@@ -300,7 +308,7 @@ curl -s "http://localhost:8080/health" | jq .
|
||||
"status": "Internal Server Error",
|
||||
// request HTTP method
|
||||
"method": "GET",
|
||||
// request hostname
|
||||
// request host name
|
||||
"host": "localhost",
|
||||
// request path
|
||||
"path": "/path",
|
||||
@@ -375,3 +383,99 @@ curl -s "http://localhost:8080/api" | jq .
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecation compatibility
|
||||
|
||||
#### Path
|
||||
|
||||
As the web provider is deprecated, you can handle the `Path` option like this:
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.dashboard]
|
||||
address = ":8080"
|
||||
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
|
||||
# Activate API and Dashboard
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
|
||||
[file]
|
||||
[backends]
|
||||
[backends.backend1]
|
||||
[backends.backend1.servers.server1]
|
||||
url = "http://127.0.0.1:8081"
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
entryPoints = ["dashboard"]
|
||||
backend = "backend1"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "PathPrefixStrip:/yourprefix;PathPrefix:/yourprefix"
|
||||
```
|
||||
|
||||
#### Address
|
||||
|
||||
As the web provider is deprecated, you can handle the `Address` option like this:
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.ping]
|
||||
address = ":8082"
|
||||
|
||||
[entryPoints.api]
|
||||
address = ":8083"
|
||||
|
||||
[ping]
|
||||
entryPoint = "ping"
|
||||
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
```
|
||||
|
||||
In the above example, you would access a regular path, administration panel, and health-check as follows:
|
||||
|
||||
* Regular path: `http://hostname:80/foo`
|
||||
* Admin Panel: `http://hostname:8083/`
|
||||
* Ping URL: `http://hostname:8082/ping`
|
||||
|
||||
In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`.
|
||||
Otherwise, you are likely to expose _all_ services via that entry point.
|
||||
|
||||
#### Authentication
|
||||
|
||||
As the web provider is deprecated, you can handle the `auth` option like this:
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.api]
|
||||
address=":8080"
|
||||
[entryPoints.api.auth]
|
||||
[entryPoints.api.auth.basic]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
|
||||
[api]
|
||||
entrypoint="api"
|
||||
```
|
||||
|
||||
For more information, see [entry points](/configuration/entrypoints/) .
|
||||
|
||||
@@ -27,9 +27,9 @@ watch = true
|
||||
# Prefix used for KV store.
|
||||
#
|
||||
# Optional
|
||||
# Default: "/traefik"
|
||||
# Default: "traefik"
|
||||
#
|
||||
prefix = "/traefik"
|
||||
prefix = "traefik"
|
||||
|
||||
# Override default configuration template.
|
||||
# For advanced users :)
|
||||
|
||||
@@ -277,6 +277,32 @@ Custom error pages are easiest to implement using the file provider.
|
||||
For dynamic providers, the corresponding template file needs to be customized accordingly and referenced in the Traefik configuration.
|
||||
|
||||
|
||||
## Rate limiting
|
||||
|
||||
Rate limiting can be configured per frontend.
|
||||
Multiple sets of rates can be added to each frontend, but the time periods must be unique.
|
||||
|
||||
```toml
|
||||
[frontends]
|
||||
[frontends.frontend1]
|
||||
# ...
|
||||
[frontends.frontend1.ratelimit]
|
||||
extractorfunc = "client.ip"
|
||||
[frontends.frontend1.ratelimit.rateset.rateset1]
|
||||
period = "10s"
|
||||
average = 100
|
||||
burst = 200
|
||||
[frontends.frontend1.ratelimit.rateset.rateset2]
|
||||
period = "3s"
|
||||
average = 5
|
||||
burst = 10
|
||||
```
|
||||
|
||||
In the above example, frontend1 is configured to limit requests by the client's ip address.
|
||||
An average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds.
|
||||
These can "burst" up to 10 and 200 in each period respectively.
|
||||
|
||||
|
||||
## Retry Configuration
|
||||
|
||||
```toml
|
||||
|
||||
@@ -1,5 +1,123 @@
|
||||
# Entry Points Definition
|
||||
|
||||
## Reference
|
||||
|
||||
### TOML
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
whitelistSourceRange = ["10.42.0.0/16", "152.89.1.33/32", "afed:be44::/16"]
|
||||
compress = true
|
||||
|
||||
[entryPoints.http.tls]
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
[[entryPoints.http.tls.certificates]]
|
||||
certFile = "path/to/my.cert"
|
||||
keyFile = "path/to/my.key"
|
||||
[[entryPoints.http.tls.certificates]]
|
||||
certFile = "path/to/other.cert"
|
||||
keyFile = "path/to/other.key"
|
||||
# ...
|
||||
[entryPoints.http.tls.clientCA]
|
||||
files = ["path/to/ca1.crt", "path/to/ca2.crt"]
|
||||
optional = false
|
||||
|
||||
[entryPoints.http.redirect]
|
||||
entryPoint = "https"
|
||||
regex = "^http://localhost/(.*)"
|
||||
replacement = "http://mydomain/$1"
|
||||
|
||||
[entryPoints.http.auth]
|
||||
headerField = "X-WebAuth-User"
|
||||
[entryPoints.http.auth.basic]
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
usersFile = "/path/to/.htpasswd"
|
||||
[entryPoints.http.auth.digest]
|
||||
users = [
|
||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
]
|
||||
usersFile = "/path/to/.htdigest"
|
||||
[entryPoints.http.auth.forward]
|
||||
address = "https://authserver.com/auth"
|
||||
trustForwardHeader = true
|
||||
[entryPoints.http.auth.forward.tls]
|
||||
ca = [ "path/to/local.crt"]
|
||||
caOptional = true
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
insecureSkipVerify = true
|
||||
|
||||
[entryPoints.http.proxyProtocol]
|
||||
insecure = true
|
||||
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
||||
|
||||
[entryPoints.http.forwardedHeaders]
|
||||
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
||||
|
||||
[entryPoints.https]
|
||||
# ...
|
||||
```
|
||||
|
||||
### CLI
|
||||
|
||||
For more information about the CLI, see the documentation about [Traefik command](/basics/#traefik).
|
||||
|
||||
```shell
|
||||
--entryPoints='Name:http Address::80'
|
||||
--entryPoints='Name:https Address::443 TLS'
|
||||
```
|
||||
|
||||
!!! note
|
||||
Whitespace is used as option separator and `,` is used as value separator for the list.
|
||||
The names of the options are case-insensitive.
|
||||
|
||||
In compose file the entrypoint syntax is different:
|
||||
|
||||
```yaml
|
||||
traefik:
|
||||
image: traefik
|
||||
command:
|
||||
- --defaultentrypoints=powpow
|
||||
- "--entryPoints=Name:powpow Address::42 Compress:true"
|
||||
```
|
||||
or
|
||||
```yaml
|
||||
traefik:
|
||||
image: traefik
|
||||
command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true'
|
||||
```
|
||||
|
||||
#### All available options:
|
||||
|
||||
```ini
|
||||
Name:foo
|
||||
Address::80
|
||||
TLS:goo,gii
|
||||
TLS
|
||||
CA:car
|
||||
CA.Optional:true
|
||||
Redirect.EntryPoint:https
|
||||
Redirect.Regex:http://localhost/(.*)
|
||||
Redirect.Replacement:http://mydomain/$1
|
||||
Compress:true
|
||||
WhiteListSourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16
|
||||
ProxyProtocol.TrustedIPs:192.168.0.1
|
||||
ProxyProtocol.Insecure:tue
|
||||
ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24
|
||||
```
|
||||
|
||||
## Basic
|
||||
|
||||
```toml
|
||||
# Entrypoints definition
|
||||
#
|
||||
@@ -51,10 +169,16 @@ To redirect an entrypoint rewriting the URL.
|
||||
```
|
||||
|
||||
!!! note
|
||||
Please note that `regex` and `replacement` do not have to be set in the `redirect` structure if an entrypoint is defined for the redirection (they will not be used in this case).
|
||||
Please note that `regex` and `replacement` do not have to be set in the `redirect` structure if an `entrypoint` is defined for the redirection (they will not be used in this case).
|
||||
|
||||
Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax.
|
||||
|
||||
Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2).
|
||||
|
||||
## TLS
|
||||
|
||||
### Static Certificates
|
||||
|
||||
Define an entrypoint with SNI support.
|
||||
|
||||
```toml
|
||||
@@ -70,6 +194,12 @@ Define an entrypoint with SNI support.
|
||||
!!! note
|
||||
If an empty TLS configuration is done, default self-signed certificates are generated.
|
||||
|
||||
|
||||
### Dynamic Certificates
|
||||
|
||||
If you need to add or remove TLS certificates while Traefik is started, Dynamic TLS certificates are supported using the [file provider](/configuration/backends/file).
|
||||
|
||||
|
||||
## TLS Mutual Authentication
|
||||
|
||||
TLS Mutual Authentication can be `optional` or not.
|
||||
@@ -100,17 +230,16 @@ In the example below both `snitest.com` and `snitest.org` will require client ce
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The deprecated argument `ClientCAFiles` allows adding Client CA files which are mandatory.
|
||||
If this parameter exists, the new ones are not checked.
|
||||
The deprecated argument `ClientCAFiles` allows adding Client CA files which are mandatory.
|
||||
If this parameter exists, the new ones are not checked.
|
||||
|
||||
## Authentication
|
||||
|
||||
### Basic Authentication
|
||||
|
||||
Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate those ones.
|
||||
Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate them.
|
||||
|
||||
Users can be specified directly in the toml file, or indirectly by referencing an external file;
|
||||
Users can be specified directly in the TOML file, or indirectly by referencing an external file;
|
||||
if both are provided, the two are merged, with external file contents having precedence.
|
||||
|
||||
```toml
|
||||
@@ -125,9 +254,9 @@ Users can be specified directly in the toml file, or indirectly by referencing a
|
||||
|
||||
### Digest Authentication
|
||||
|
||||
You can use `htdigest` to generate those ones.
|
||||
You can use `htdigest` to generate them.
|
||||
|
||||
Users can be specified directly in the toml file, or indirectly by referencing an external file;
|
||||
Users can be specified directly in the TOML file, or indirectly by referencing an external file;
|
||||
if both are provided, the two are merged, with external file contents having precedence
|
||||
|
||||
```toml
|
||||
@@ -135,8 +264,8 @@ Users can be specified directly in the toml file, or indirectly by referencing a
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.auth.basic]
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05 ", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
[entryPoints.http.auth.digest]
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
usersFile = "/path/to/.htdigest"
|
||||
```
|
||||
|
||||
@@ -145,7 +274,7 @@ Users can be specified directly in the toml file, or indirectly by referencing a
|
||||
This configuration will first forward the request to `http://authserver.com/auth`.
|
||||
|
||||
If the response code is 2XX, access is granted and the original request is performed.
|
||||
Otherwise, the response from the auth server is returned.
|
||||
Otherwise, the response from the authentication server is returned.
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
@@ -154,7 +283,7 @@ Otherwise, the response from the auth server is returned.
|
||||
# To enable forward auth on an entrypoint
|
||||
[entryPoints.http.auth.forward]
|
||||
address = "https://authserver.com/auth"
|
||||
|
||||
|
||||
# Trust existing X-Forwarded-* headers.
|
||||
# Useful with another reverse proxy in front of Traefik.
|
||||
#
|
||||
@@ -162,7 +291,7 @@ Otherwise, the response from the auth server is returned.
|
||||
# Default: false
|
||||
#
|
||||
trustForwardHeader = true
|
||||
|
||||
|
||||
# Enable forward auth TLS connection.
|
||||
#
|
||||
# Optional
|
||||
@@ -182,7 +311,10 @@ To specify an https entry point with a minimum TLS version, and specifying an ar
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
minVersion = "VersionTLS12"
|
||||
cipherSuites = ["TLS_RSA_WITH_AES_256_GCM_SHA384"]
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
[[entryPoints.https.tls.certificates]]
|
||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
||||
@@ -226,7 +358,7 @@ Only IPs in `trustedIPs` will lead to remote client address replacement: you sho
|
||||
|
||||
!!! danger
|
||||
When queuing Træfik behind another load-balancer, be sure to carefully configure Proxy Protocol on both sides.
|
||||
Otherwise, it could introduce a security risk in your system by forging requests.
|
||||
Otherwise, it could introduce a security risk in your system by forging requests.
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Ping Definition
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml
|
||||
# Ping definition
|
||||
[ping]
|
||||
@@ -19,7 +21,7 @@
|
||||
!!! warning
|
||||
Even if you have authentication configured on entry point, the `/ping` path of the api is excluded from authentication.
|
||||
|
||||
### Example
|
||||
## Example
|
||||
|
||||
```shell
|
||||
curl -sv "http://localhost:8080/ping"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[](https://twitter.com/intent/follow?screen_name=traefikproxy)
|
||||
|
||||
|
||||
Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
Træfik (pronounced like _traffic_) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
It supports several backends ([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 a lot more) to manage its configuration automatically and dynamically.
|
||||
|
||||
## Overview
|
||||
@@ -22,7 +22,7 @@ If you want your users to access some of your microservices from the Internet, y
|
||||
- path `domain.com/web` will point the microservice `web` in your private network
|
||||
- domain `backoffice.domain.com` will point the microservices `backoffice` in your private network, load-balancing between your multiple instances
|
||||
|
||||
But a microservices architecture is dynamic... Services are added, removed, killed or upgraded often, eventually several times a day.
|
||||
Microservices are often deployed in dynamic environments where services are added, removed, killed, upgraded or scaled many times a day.
|
||||
|
||||
Traditional reverse-proxies are not natively dynamic. You can't change their configuration and hot-reload easily.
|
||||
|
||||
@@ -108,7 +108,7 @@ version: '2'
|
||||
services:
|
||||
proxy:
|
||||
image: traefik
|
||||
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
|
||||
command: --api --docker --docker.domain=docker.localhost --logLevel=DEBUG
|
||||
networks:
|
||||
- webgateway
|
||||
ports:
|
||||
@@ -129,7 +129,7 @@ Start it from within the `traefik` folder:
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
In a browser you may open [http://localhost:8080](http://localhost:8080) to access Træfik's dashboard and observe the following magic.
|
||||
In a browser, you may open [http://localhost:8080](http://localhost:8080) to access Træfik's dashboard and observe the following magic.
|
||||
|
||||
Now, create a folder named `test` and create a `docker-compose.yml` in it with this content:
|
||||
|
||||
|
||||
4
docs/theme/partials/footer.html
vendored
4
docs/theme/partials/footer.html
vendored
@@ -20,7 +20,7 @@
|
||||
IN THE SOFTWARE.
|
||||
-->
|
||||
|
||||
{% import "partials/language.html" as lang %}
|
||||
{% import "partials/language.html" as lang with context %}
|
||||
|
||||
<!-- Application footer -->
|
||||
<footer class="md-footer">
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
<!-- Social links -->
|
||||
{% block social %}
|
||||
{% include "partials/social.html" %}
|
||||
{% include "partials/social.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
294
docs/user-guide/cluster-docker-consul.md
Normal file
294
docs/user-guide/cluster-docker-consul.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# Clustering / High Availability on Docker Swarm with Consul
|
||||
|
||||
This guide explains how to use Træfik in high availability mode in a Docker Swarm and with Let's Encrypt.
|
||||
|
||||
Why do we need Træfik in cluster mode? Running multiple instances should work out of the box?
|
||||
|
||||
If you want to use Let's Encrypt with Træfik, sharing configuration or TLS certificates between many Træfik instances, you need Træfik cluster/HA.
|
||||
|
||||
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.
|
||||
|
||||
For more information about challenge: [Automatic Certificate Management Environment (ACME)](https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#tls-with-server-name-indication-tls-sni)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You will need a working Docker Swarm cluster.
|
||||
|
||||
## Træfik configuration
|
||||
|
||||
In this guide, we will not use a TOML configuration file, but only command line flag.
|
||||
With that, we can use the base image without mounting configuration file or building custom image.
|
||||
|
||||
What Træfik should do:
|
||||
|
||||
- Listen to 80 and 443
|
||||
- Redirect HTTP traffic to HTTPS
|
||||
- Generate SSL certificate when a domain is added
|
||||
- Listen to Docker Swarm event
|
||||
|
||||
### EntryPoints configuration
|
||||
|
||||
TL;DR:
|
||||
|
||||
```shell
|
||||
$ traefik \
|
||||
--entrypoints='Name:http Address::80 Redirect.EntryPoint:https' \
|
||||
--entrypoints='Name:https Address::443 TLS' \
|
||||
--defaultentrypoints=http,https
|
||||
```
|
||||
|
||||
To listen to different ports, we need to create an entry point for each.
|
||||
|
||||
The CLI syntax is `--entrypoints='Name:a_name Address:an_ip_or_empty:a_port options'`.
|
||||
If you want to redirect traffic from one entry point to another, it's the option `Redirect.EntryPoint:entrypoint_name`.
|
||||
|
||||
By default, we don't want to configure all our services to listen on http and https, we add a default entry point configuration: `--defaultentrypoints=http,https`.
|
||||
|
||||
### Let's Encrypt configuration
|
||||
|
||||
TL;DR:
|
||||
|
||||
```shell
|
||||
$ traefik \
|
||||
--acme \
|
||||
--acme.storage=/etc/traefik/acme/acme.json \
|
||||
--acme.entryPoint=https \
|
||||
--acme.httpChallenge.entryPoint=http \
|
||||
--acme.email=contact@mydomain.ca
|
||||
```
|
||||
|
||||
Let's Encrypt needs 4 parameters: an TLS entry point to listen to, a non-TLS entry point to allow HTTP challenges, a storage for certificates, and an email for the registration.
|
||||
|
||||
To enable Let's Encrypt support, you need to add `--acme` flag.
|
||||
|
||||
Now, Træfik needs to know where to store the certificates, we can choose between a key in a Key-Value store, or a file path: `--acme.storage=my/key` or `--acme.storage=/path/to/acme.json`.
|
||||
|
||||
The `acme.httpChallenge.entryPoint` flag enables the `HTTP-01` challenge and specifies the entryPoint to use during the challenges.
|
||||
|
||||
For your email and the entry point, it's `--acme.entryPoint` and `--acme.email` flags.
|
||||
|
||||
### Docker configuration
|
||||
|
||||
TL;DR:
|
||||
|
||||
```shell
|
||||
$ traefik \
|
||||
--docker \
|
||||
--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 watch docker events, add `--docker.watch`.
|
||||
|
||||
### Full docker-compose file
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:1.5
|
||||
command:
|
||||
- "--api"
|
||||
- "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
|
||||
- "--entrypoints=Name:https Address::443 TLS"
|
||||
- "--defaultentrypoints=http,https"
|
||||
- "--acme"
|
||||
- "--acme.storage=/etc/traefik/acme/acme.json"
|
||||
- "--acme.entryPoint=https"
|
||||
- "--acme.httpChallenge.entryPoint=http"
|
||||
- "--acme.OnHostRule=true"
|
||||
- "--acme.onDemand=false"
|
||||
- "--acme.email=contact@mydomain.ca"
|
||||
- "--docker"
|
||||
- "--docker.swarmmode"
|
||||
- "--docker.domain=mydomain.ca"
|
||||
- "--docker.watch"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- webgateway
|
||||
- traefik
|
||||
ports:
|
||||
- target: 80
|
||||
published: 80
|
||||
mode: host
|
||||
- target: 443
|
||||
published: 443
|
||||
mode: host
|
||||
- target: 8080
|
||||
published: 8080
|
||||
mode: host
|
||||
deploy:
|
||||
mode: global
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
update_config:
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
networks:
|
||||
webgateway:
|
||||
driver: overlay
|
||||
external: true
|
||||
traefik:
|
||||
driver: overlay
|
||||
```
|
||||
|
||||
## Migrate configuration to Consul
|
||||
|
||||
We created a special Træfik command to help configuring your Key Value store from a Træfik TOML configuration file and/or CLI flags.
|
||||
|
||||
## Deploy a Træfik cluster
|
||||
|
||||
The best way we found is to have an initializer service.
|
||||
This service will push the config to Consul via the `storeconfig` sub-command.
|
||||
|
||||
This service will retry until finishing without error because Consul may not be ready when the service tries to push the configuration.
|
||||
|
||||
The initializer in a docker-compose file will be:
|
||||
|
||||
```yaml
|
||||
traefik_init:
|
||||
image: traefik:1.5
|
||||
command:
|
||||
- "storeconfig"
|
||||
- "--api"
|
||||
[...]
|
||||
- "--consul"
|
||||
- "--consul.endpoint=consul:8500"
|
||||
- "--consul.prefix=traefik"
|
||||
networks:
|
||||
- traefik
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
depends_on:
|
||||
- consul
|
||||
```
|
||||
|
||||
And now, the Træfik part will only have the Consul configuration.
|
||||
|
||||
```yaml
|
||||
traefik:
|
||||
image: traefik:1.5
|
||||
depends_on:
|
||||
- traefik_init
|
||||
- consul
|
||||
command:
|
||||
- "--consul"
|
||||
- "--consul.endpoint=consul:8500"
|
||||
- "--consul.prefix=traefik"
|
||||
[...]
|
||||
```
|
||||
|
||||
!!! note
|
||||
For Træfik <1.5.0 add `acme.storage=traefik/acme/account` because Træfik is not reading it from Consul.
|
||||
|
||||
If you have some update to do, update the initializer service and re-deploy it.
|
||||
The new configuration will be stored in Consul, and you need to restart the Træfik node: `docker service update --force traefik_traefik`.
|
||||
|
||||
## Full docker-compose file
|
||||
|
||||
```yaml
|
||||
version: "3.4"
|
||||
services:
|
||||
traefik_init:
|
||||
image: traefik:1.5
|
||||
command:
|
||||
- "storeconfig"
|
||||
- "--api"
|
||||
- "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
|
||||
- "--entrypoints=Name:https Address::443 TLS"
|
||||
- "--defaultentrypoints=http,https"
|
||||
- "--acme"
|
||||
- "--acme.storage=traefik/acme/account"
|
||||
- "--acme.entryPoint=https"
|
||||
- "--acme.httpChallenge.entryPoint=http"
|
||||
- "--acme.OnHostRule=true"
|
||||
- "--acme.onDemand=false"
|
||||
- "--acme.email=foobar@example.com"
|
||||
- "--docker"
|
||||
- "--docker.swarmmode"
|
||||
- "--docker.domain=example.com"
|
||||
- "--docker.watch"
|
||||
- "--consul"
|
||||
- "--consul.endpoint=consul:8500"
|
||||
- "--consul.prefix=traefik"
|
||||
networks:
|
||||
- traefik
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
depends_on:
|
||||
- consul
|
||||
traefik:
|
||||
image: traefik:1.5
|
||||
depends_on:
|
||||
- traefik_init
|
||||
- consul
|
||||
command:
|
||||
- "--consul"
|
||||
- "--consul.endpoint=consul:8500"
|
||||
- "--consul.prefix=traefik"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- webgateway
|
||||
- traefik
|
||||
ports:
|
||||
- target: 80
|
||||
published: 80
|
||||
mode: host
|
||||
- target: 443
|
||||
published: 443
|
||||
mode: host
|
||||
- target: 8080
|
||||
published: 8080
|
||||
mode: host
|
||||
deploy:
|
||||
mode: global
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
update_config:
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
consul:
|
||||
image: consul
|
||||
command: agent -server -bootstrap-expect=1
|
||||
volumes:
|
||||
- consul-data:/consul/data
|
||||
environment:
|
||||
- CONSUL_LOCAL_CONFIG={"datacenter":"us_east2","server":true}
|
||||
- CONSUL_BIND_INTERFACE=eth0
|
||||
- CONSUL_CLIENT_INTERFACE=eth0
|
||||
deploy:
|
||||
replicas: 1
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
networks:
|
||||
webgateway:
|
||||
driver: overlay
|
||||
external: true
|
||||
traefik:
|
||||
driver: overlay
|
||||
|
||||
volumes:
|
||||
consul-data:
|
||||
driver: [not local]
|
||||
```
|
||||
@@ -23,3 +23,11 @@ A Træfik cluster is based on a manager/worker model.
|
||||
|
||||
When starting, Træfik will elect a manager.
|
||||
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).**
|
||||
|
||||
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.
|
||||
@@ -69,7 +69,7 @@ networks:
|
||||
```
|
||||
|
||||
As you can see, we're mounting the `traefik.toml` file as well as the (empty) `acme.json` file in the container.
|
||||
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Træfik can listen to Docker events and reconfigure it's own internal configuration when containers are created (or shut down).
|
||||
Also, we're mounting the `/var/run/docker.sock` Docker socket in the container as well, so Træfik can listen to Docker events and reconfigure its own internal configuration when containers are created (or shut down).
|
||||
Also, we're making sure the container is automatically restarted by the Docker engine in case of problems (or: if the server is rebooted).
|
||||
We're publishing the default HTTP ports `80` and `443` on the host, and making sure the container is placed within the `web` network we've created earlier on.
|
||||
Finally, we're giving this container a static name called `traefik`.
|
||||
@@ -104,11 +104,13 @@ email = "your-email-here@my-awesome-app.org"
|
||||
storage = "acme.json"
|
||||
entryPoint = "https"
|
||||
OnHostRule = true
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
```
|
||||
|
||||
This is the minimum configuration required to do the following:
|
||||
|
||||
- Log `ERROR`-level messages (or more severe) to the console, but silence `DEBUG`-level messagse
|
||||
- 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!**
|
||||
@@ -197,7 +199,7 @@ Since the `traefik` container we've created and started earlier is also attached
|
||||
As mentioned earlier, we don't want containers exposed automatically by Træfik.
|
||||
|
||||
The reason behind this is simple: we want to have control over this process ourselves.
|
||||
Thanks to Docker labels, we can tell Træfik how to create it's internal routing configuration.
|
||||
Thanks to Docker labels, we can tell Træfik how to create its internal routing configuration.
|
||||
|
||||
Let's take a look at the labels themselves for the `app` service, which is a HTTP webservice listing on port 9000:
|
||||
|
||||
@@ -220,7 +222,7 @@ 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.
|
||||
With the `traefik.enable` label, we tell Træfik to include this container in it's internal configuration.
|
||||
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.
|
||||
|
||||
@@ -6,6 +6,7 @@ You will find here some configuration examples of Træfik.
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
@@ -15,6 +16,7 @@ defaultEntryPoints = ["http"]
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
@@ -34,6 +36,7 @@ Note that we can either give path to certificate file or directly the file conte
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
@@ -52,10 +55,16 @@ defaultEntryPoints = ["http", "https"]
|
||||
|
||||
## Let's Encrypt support
|
||||
|
||||
### Basic example
|
||||
!!! note
|
||||
Even if `TLS-SNI-01` challenge is [disabled](https://community.letsencrypt.org/t/2018-01-11-update-regarding-acme-tls-sni-and-shared-hosting-infrastructure/50188), for the moment, it stays the _by default_ ACME Challenge in Træfik but all the examples use the `HTTP-01` challenge (except DNS challenge examples).
|
||||
If `TLS-SNI-01` challenge is not re-enabled in the future, it we will be removed from Træfik.
|
||||
|
||||
### Basic example with HTTP challenge
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
@@ -65,6 +74,8 @@ email = "test@traefik.io"
|
||||
storage = "acme.json"
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
|
||||
[[acme.domains]]
|
||||
main = "local1.com"
|
||||
@@ -78,14 +89,16 @@ entryPoint = "https"
|
||||
main = "local4.com"
|
||||
```
|
||||
|
||||
This configuration allows generating Let's Encrypt certificates for the four domains `local[1-4].com` with described SANs.
|
||||
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com` with described SANs.
|
||||
|
||||
Traefik generates these certificates when it starts and it needs to be restart if new domains are added.
|
||||
Træfik generates these certificates when it starts and it needs to be restart if new domains are added.
|
||||
|
||||
### OnHostRule option
|
||||
### OnHostRule option (with HTTP challenge)
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
@@ -96,6 +109,8 @@ storage = "acme.json"
|
||||
onHostRule = true
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
|
||||
[[acme.domains]]
|
||||
main = "local1.com"
|
||||
@@ -109,16 +124,18 @@ entryPoint = "https"
|
||||
main = "local4.com"
|
||||
```
|
||||
|
||||
This configuration allows generating Let's Encrypt certificates for the four domains `local[1-4].com`.
|
||||
This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com`.
|
||||
|
||||
Traefik generates these certificates when it starts.
|
||||
Træfik generates these certificates when it starts.
|
||||
|
||||
If a backend is added with a `onHost` rule, Traefik will automatically generate the Let's Encrypt certificate for the new domain.
|
||||
If a backend is added with a `onHost` rule, Træfik will automatically generate the Let's Encrypt certificate for the new domain (for frontends wired on the `acme.entryPoint`).
|
||||
|
||||
### OnDemand option
|
||||
### OnDemand option (with HTTP challenge)
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
@@ -129,15 +146,16 @@ storage = "acme.json"
|
||||
onDemand = true
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
```
|
||||
|
||||
This configuration allows generating a Let's Encrypt certificate during the first HTTPS request on a new domain.
|
||||
|
||||
This configuration allows generating a Let's Encrypt certificate (thanks to `HTTP-01` challenge) during the first HTTPS request on a new domain.
|
||||
|
||||
!!! note
|
||||
This option simplifies the configuration but :
|
||||
|
||||
* TLS handshakes will be slow when requesting a hostname certificate for the first time, this can leads to DDoS attacks.
|
||||
* TLS handshakes will be slow when requesting a host name certificate for the first time, this can leads to DDoS attacks.
|
||||
* Let's Encrypt have rate limiting: https://letsencrypt.org/docs/rate-limits
|
||||
|
||||
That's why, it's better to use the `onHostRule` option if possible.
|
||||
@@ -153,10 +171,11 @@ This configuration allows generating a Let's Encrypt certificate during the firs
|
||||
[acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "acme.json"
|
||||
dnsProvider = "digitalocean" # DNS Provider name (cloudflare, OVH, gandi...)
|
||||
delayDontCheckDNS = 0
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
[acme.dnsChallenge]
|
||||
provider = "digitalocean" # DNS Provider name (cloudflare, OVH, gandi...)
|
||||
delayBeforeCheck = 0
|
||||
|
||||
[[acme.domains]]
|
||||
main = "local1.com"
|
||||
@@ -171,14 +190,16 @@ entryPoint = "https"
|
||||
```
|
||||
|
||||
DNS challenge needs environment variables to be executed.
|
||||
This variables have to be set on the machine/container which host Traefik.
|
||||
These variables have to be set on the machine/container which host Træfik.
|
||||
|
||||
These variables are described [in this section](/configuration/acme/#dnsprovider).
|
||||
These variables are described [in this section](/configuration/acme/#provider).
|
||||
|
||||
### OnHostRule option and provided certificates
|
||||
### OnHostRule option and provided certificates (with HTTP challenge)
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
@@ -192,10 +213,11 @@ storage = "acme.json"
|
||||
onHostRule = true
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
```
|
||||
|
||||
Traefik will only try to generate a Let's encrypt certificate if the domain cannot be checked by the provided certificates.
|
||||
Træfik will only try to generate a Let's encrypt certificate (thanks to `HTTP-01` challenge) if the domain cannot be checked by the provided certificates.
|
||||
|
||||
### Cluster mode
|
||||
|
||||
@@ -207,6 +229,8 @@ Before you use Let's Encrypt in a Traefik cluster, take a look to [the key-value
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
@@ -217,6 +241,9 @@ storage = "traefik/acme/account"
|
||||
caServer = "http://172.18.0.1:4000/directory"
|
||||
entryPoint = "https"
|
||||
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
|
||||
[[acme.domains]]
|
||||
main = "local1.com"
|
||||
sans = ["test1.local1.com", "test2.local1.com"]
|
||||
@@ -244,10 +271,12 @@ The `consul` provider contains the configuration.
|
||||
|
||||
```toml
|
||||
[frontends]
|
||||
|
||||
[frontends.frontend1]
|
||||
backend = "backend2"
|
||||
[frontends.frontend1.routes.test_1]
|
||||
rule = "Host:test.localhost"
|
||||
|
||||
[frontends.frontend2]
|
||||
backend = "backend1"
|
||||
passHostHeader = true
|
||||
@@ -255,23 +284,25 @@ The `consul` provider contains the configuration.
|
||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||
[frontends.frontend2.routes.test_1]
|
||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||
|
||||
[frontends.frontend3]
|
||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||
backend = "backend2"
|
||||
rule = "Path:/test"
|
||||
rule = "Path:/test"
|
||||
```
|
||||
|
||||
## Enable Basic authentication in an entrypoint
|
||||
## 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 those ones.
|
||||
Passwords are encoded in MD5: you can use `htpasswd` to generate them.
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
@@ -286,6 +317,7 @@ via a configurable header value.
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
@@ -304,49 +336,45 @@ providersThrottleDuration = "5s"
|
||||
idleTimeout = "360s"
|
||||
```
|
||||
|
||||
## Securing Ping Health Check
|
||||
## Ping Health Check
|
||||
|
||||
The `/ping` health-check URL is enabled together with the web admin panel, enabled with the command-line `--web` or config file option `[web]`.
|
||||
The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`.
|
||||
Thus, if you have a regular path for `/foo` and an entrypoint on `:80`, you would access them as follows:
|
||||
|
||||
* Regular path: `http://hostname:80/foo`
|
||||
* Admin panel: `http://hostname:8080/`
|
||||
* Ping URL: `http://hostname:8080/ping`
|
||||
|
||||
However, for security reasons, you may want to be able to expose the `/ping` health-check URL to outside health-checkers, e.g. an Internet service or cloud load-balancer, _without_ exposing your admin panel's port.
|
||||
However, for security reasons, you may want to be able to expose the `/ping` health-check URL to outside health-checkers, e.g. an Internet service or cloud load-balancer, _without_ exposing your administration panel's port.
|
||||
In many environments, the security staff may not _allow_ you to expose it.
|
||||
|
||||
You have two options:
|
||||
|
||||
* Enable `/ping` on a regular entrypoint
|
||||
* Enable `/ping` on a regular entry point
|
||||
* Enable `/ping` on a dedicated port
|
||||
|
||||
### Enable ping health check on a regular entrypoint
|
||||
### Enable ping health check on a regular entry point
|
||||
|
||||
To proxy `/ping` from a regular entrypoint to the admin one without exposing the panel, do the following:
|
||||
To proxy `/ping` from a regular entry point to the administration one without exposing the panel, do the following:
|
||||
|
||||
```toml
|
||||
[backends]
|
||||
[backends.traefik]
|
||||
[backends.traefik.servers.server1]
|
||||
url = "http://localhost:8080"
|
||||
weight = 10
|
||||
defaultEntryPoints = ["http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
||||
[ping]
|
||||
entryPoint = "http"
|
||||
|
||||
[frontends]
|
||||
[frontends.traefikadmin]
|
||||
backend = "traefik"
|
||||
[frontends.traefikadmin.routes.ping]
|
||||
rule = "Path:/ping"
|
||||
```
|
||||
|
||||
The above creates a new backend called `traefik`, listening on `http://localhost:8080`, i.e. the local admin port.
|
||||
We only expose the admin panel via the `frontend` named `traefikadmin`, and only expose the `/ping` Path.
|
||||
Be careful with the `traefikadmin` frontend. If you do _not_ specify a `Path:` rule, you would expose the entire dashboard.
|
||||
The above link `ping` on the `http` entry point and then expose it on port `80`
|
||||
|
||||
### Enable ping health check on dedicated port
|
||||
|
||||
If you do not want to or cannot expose the health-check on a regular entrypoint - e.g. your security rules do not allow it, or you have a conflicting path - then you can enable health-check on its own entrypoint.
|
||||
Use the following config:
|
||||
If you do not want to or cannot expose the health-check on a regular entry point - e.g. your security rules do not allow it, or you have a conflicting path - then you can enable health-check on its own entry point.
|
||||
Use the following configuration:
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http"]
|
||||
@@ -357,32 +385,18 @@ defaultEntryPoints = ["http"]
|
||||
[entryPoints.ping]
|
||||
address = ":8082"
|
||||
|
||||
[backends]
|
||||
[backends.traefik]
|
||||
[backends.traefik.servers.server1]
|
||||
url = "http://localhost:8080"
|
||||
weight = 10
|
||||
|
||||
[frontends]
|
||||
[frontends.traefikadmin]
|
||||
backend = "traefik"
|
||||
entrypoints = ["ping"]
|
||||
[frontends.traefikadmin.routes.ping]
|
||||
rule = "Path:/ping"
|
||||
[ping]
|
||||
entryPoint = "ping"
|
||||
```
|
||||
|
||||
The above is similar to the previous example, but instead of enabling `/ping` on the _default_ entrypoint, we enable it on a _dedicated_ entrypoint.
|
||||
The above is similar to the previous example, but instead of enabling `/ping` on the _default_ entry point, we enable it on a _dedicated_ entry point.
|
||||
|
||||
In the above example, you would access a regular path, admin panel and health-check as follows:
|
||||
In the above example, you would access a regular path and health-check as follows:
|
||||
|
||||
* Regular path: `http://hostname:80/foo`
|
||||
* Admin panel: `http://hostname:8080/`
|
||||
* Ping URL: `http://hostname:8082/ping`
|
||||
|
||||
Note the dedicated port `:8082` for `/ping`.
|
||||
|
||||
In the above example, it is _very_ important to create a named dedicated entrypoint, and do **not** include it in `defaultEntryPoints`.
|
||||
Otherwise, you are likely to expose _all_ services via that entrypoint.
|
||||
|
||||
In the above example, we have two entrypoints, `http` and `ping`, but we only included `http` in `defaultEntryPoints`, while explicitly tying `frontend.traefikadmin` to the `ping` entrypoint.
|
||||
This ensures that all the "normal" frontends will be exposed via entrypoint `http` and _not_ via entrypoint `ping`.
|
||||
In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`.
|
||||
Otherwise, you are likely to expose _all_ services via this entry point.
|
||||
|
||||
@@ -57,8 +57,7 @@ RootCAs = [ "./backend.cert" ]
|
||||
keyFile = "./frontend.key"
|
||||
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Kubernetes Ingress Controller
|
||||
|
||||
This guide explains how to use Træfik as an Ingress controller in a Kubernetes cluster.
|
||||
This guide explains how to use Træfik as an Ingress controller for a Kubernetes cluster.
|
||||
|
||||
If you are not familiar with Ingresses in Kubernetes you might want to read the [Kubernetes user guide](https://kubernetes.io/docs/concepts/services-networking/ingress/)
|
||||
|
||||
@@ -8,8 +8,10 @@ The config files used in this guide can be found in the [examples directory](htt
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A working Kubernetes cluster. If you want to follow along with this guide, you should setup [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/)
|
||||
on your machine, as it is the quickest way to get a local Kubernetes cluster setup for experimentation and development.
|
||||
1. A working Kubernetes cluster. If you want to follow along with this guide, you should setup [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/) on your machine, as it is the quickest way to get a local Kubernetes cluster setup for experimentation and development.
|
||||
|
||||
!!! note
|
||||
The guide is likely not fully adequate for a production-ready setup.
|
||||
|
||||
2. The `kubectl` binary should be [installed on your workstation](https://kubernetes.io/docs/getting-started-guides/minikube/#download-kubectl).
|
||||
|
||||
@@ -79,8 +81,8 @@ 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 DeaemonSet.
|
||||
- It is possible to exclusively run a Service on a dedicated set of machines using taints and tolerations with a DaemonSet.
|
||||
- The scalability is much better when using a Deployment, because you will have a Single-Pod-per-Node model when using the DeaemonSet.
|
||||
- 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 Deployment objects looks like this:
|
||||
@@ -117,7 +119,7 @@ spec:
|
||||
- image: traefik
|
||||
name: traefik-ingress-lb
|
||||
args:
|
||||
- --web
|
||||
- --api
|
||||
- --kubernetes
|
||||
---
|
||||
kind: Service
|
||||
@@ -137,6 +139,7 @@ spec:
|
||||
name: admin
|
||||
type: NodePort
|
||||
```
|
||||
|
||||
[examples/k8s/traefik-deployment.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/traefik-deployment.yaml)
|
||||
|
||||
!!! note
|
||||
@@ -182,7 +185,7 @@ spec:
|
||||
privileged: true
|
||||
args:
|
||||
- -d
|
||||
- --web
|
||||
- --api
|
||||
- --kubernetes
|
||||
---
|
||||
kind: Service
|
||||
@@ -233,7 +236,7 @@ Start by listing the pods in the `kube-system` namespace:
|
||||
kubectl --namespace=kube-system get pods
|
||||
```
|
||||
|
||||
```
|
||||
```shell
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
kube-addon-manager-minikubevm 1/1 Running 0 4h
|
||||
kubernetes-dashboard-s8krj 1/1 Running 0 4h
|
||||
@@ -250,40 +253,45 @@ _It might take a few moments for kubernetes to pull the Træfik image and start
|
||||
|
||||
You should now be able to access Træfik on port 80 of your Minikube instance when using the DaemonSet:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
curl $(minikube ip)
|
||||
```
|
||||
```
|
||||
|
||||
```shell
|
||||
404 page not found
|
||||
```
|
||||
|
||||
If you decided to use the deployment, then you need to target the correct NodePort, which can be seen then you execute `kubectl get services --namespace=kube-system`.
|
||||
If you decided to use the deployment, then you need to target the correct NodePort, which can be seen when you execute `kubectl get services --namespace=kube-system`.
|
||||
|
||||
```sh
|
||||
```shell
|
||||
curl $(minikube ip):<NODEPORT>
|
||||
```
|
||||
```
|
||||
|
||||
```shell
|
||||
404 page not found
|
||||
```
|
||||
|
||||
!!! note
|
||||
We expect to see a 404 response here as we haven't yet given Træfik any configuration.
|
||||
|
||||
All further examples below assume a DaemonSet installation. Deployment users will need to append the NodePort when constructing requests.
|
||||
|
||||
## Deploy Træfik using Helm Chart
|
||||
|
||||
Instead of installing Træfik via an own object, you can also use the Træfik Helm chart.
|
||||
!!! note
|
||||
The Helm Chart is maintained by the community, not the Traefik project maintainers.
|
||||
|
||||
This allows more complex configuration via Kubernetes [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configmap/) and enabled TLS certificates.
|
||||
Instead of installing Træfik via Kubernetes object directly, you can also use the Træfik Helm chart.
|
||||
|
||||
Install Træfik chart by:
|
||||
Install the Træfik chart by:
|
||||
|
||||
```shell
|
||||
helm install stable/traefik
|
||||
```
|
||||
|
||||
For more information, check out [the doc](https://github.com/kubernetes/charts/tree/master/stable/traefik).
|
||||
For more information, check out [the documentation](https://github.com/kubernetes/charts/tree/master/stable/traefik).
|
||||
|
||||
## Submitting An Ingress to the cluster.
|
||||
## Submitting an Ingress to the Cluster
|
||||
|
||||
Lets start by creating a Service and an Ingress that will expose the [Træfik Web UI](https://github.com/containous/traefik#web-ui).
|
||||
|
||||
@@ -316,30 +324,29 @@ spec:
|
||||
serviceName: traefik-web-ui
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
[examples/k8s/ui.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/ui.yaml)
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/ui.yaml
|
||||
```
|
||||
|
||||
Now lets setup an entry in our /etc/hosts file to route `traefik-ui.minikube` to our cluster.
|
||||
Now lets setup an entry in our `/etc/hosts` file to route `traefik-ui.minikube` to our cluster.
|
||||
|
||||
In production you would want to set up real dns entries.
|
||||
You can get the ip address of your minikube instance by running `minikube ip`
|
||||
In production you would want to set up real DNS entries.
|
||||
You can get the IP address of your minikube instance by running `minikube ip`:
|
||||
|
||||
```shell
|
||||
echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts
|
||||
```
|
||||
|
||||
We should now be able to visit [traefik-ui.minikube](http://traefik-ui.minikube) in the browser and view the Træfik Web UI.
|
||||
We should now be able to visit [traefik-ui.minikube](http://traefik-ui.minikube) in the browser and view the Træfik web UI.
|
||||
|
||||
## Basic Authentication
|
||||
|
||||
It's possible to add additional authentication annotations in the Ingress rule.
|
||||
The source of the authentication is a secret that contains usernames and passwords inside the key auth.
|
||||
To read about basic auth limitations see the [Kubernetes Ingress](/configuration/backends/kubernetes) configuration page.
|
||||
It's possible to protect access to Traefik through basic authentication. (See the [Kubernetes Ingress](/configuration/backends/kubernetes) configuration page for syntactical details and restrictions.)
|
||||
|
||||
#### Creating the Secret
|
||||
### Creating the Secret
|
||||
|
||||
A. Use `htpasswd` to create a file containing the username and the base64-encoded password:
|
||||
|
||||
@@ -353,25 +360,28 @@ You will be prompted for a password which you will have to enter twice.
|
||||
```shell
|
||||
cat auth
|
||||
```
|
||||
```
|
||||
|
||||
```shell
|
||||
myusername:$apr1$78Jyn/1K$ERHKVRPPlzAX8eBtLuvRZ0
|
||||
```
|
||||
|
||||
B. Now use `kubectl` to create a secret in the monitoring namespace using the file created by `htpasswd`.
|
||||
B. Now use `kubectl` to create a secret in the `monitoring` namespace using the file created by `htpasswd`.
|
||||
|
||||
```shell
|
||||
kubectl create secret generic mysecret --from-file auth --namespace=monitoring
|
||||
```
|
||||
|
||||
!!! note
|
||||
Secret must be in same namespace as the ingress rule.
|
||||
Secret must be in same namespace as the Ingress object.
|
||||
|
||||
C. Create the ingress using the following annotations to specify basic auth and that the username and password is stored in `mysecret`.
|
||||
C. Attach the following annotations to the Ingress object:
|
||||
|
||||
- `ingress.kubernetes.io/auth-type: "basic"`
|
||||
- `ingress.kubernetes.io/auth-secret: "mysecret"`
|
||||
|
||||
Following is a full ingress example based on Prometheus:
|
||||
They specify basic authentication and reference the Secret `mysecret` containing the credentials.
|
||||
|
||||
Following is a full Ingress example based on Prometheus:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -393,17 +403,17 @@ spec:
|
||||
servicePort: 9090
|
||||
```
|
||||
|
||||
You can apply the example ingress as following:
|
||||
You can apply the example as following:
|
||||
|
||||
```shell
|
||||
kubectl create -f prometheus-ingress.yaml -n monitoring
|
||||
```
|
||||
|
||||
## Name based routing
|
||||
## Name-based Routing
|
||||
|
||||
In this example we are going to setup websites for 3 of the United Kingdoms best loved cheeses, Cheddar, Stilton and Wensleydale.
|
||||
In this example we are going to setup websites for three of the United Kingdoms best loved cheeses: Cheddar, Stilton, and Wensleydale.
|
||||
|
||||
First lets start by launching the 3 pods for the cheese websites.
|
||||
First lets start by launching the pods for the cheese websites.
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -485,13 +495,14 @@ spec:
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
[examples/k8s/cheese-deployments.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheese-deployments.yaml)
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheese-deployments.yaml
|
||||
```
|
||||
|
||||
Next we need to setup a service for each of the cheese pods.
|
||||
Next we need to setup a Service for each of the cheese pods.
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -540,7 +551,6 @@ spec:
|
||||
!!! note
|
||||
We also set a [circuit breaker expression](/basics/#backends) for one of the backends by setting the `traefik.backend.circuitbreaker` annotation on the service.
|
||||
|
||||
|
||||
[examples/k8s/cheese-services.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheese-services.yaml)
|
||||
|
||||
```shell
|
||||
@@ -580,6 +590,7 @@ spec:
|
||||
serviceName: wensleydale
|
||||
servicePort: http
|
||||
```
|
||||
|
||||
[examples/k8s/cheese-ingress.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheese-ingress.yaml)
|
||||
|
||||
!!! note
|
||||
@@ -590,7 +601,7 @@ kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/exa
|
||||
```
|
||||
|
||||
Now visit the [Træfik dashboard](http://traefik-ui.minikube/) and you should see a frontend for each host.
|
||||
Along with a backend listing for each service with a Server set up for each pod.
|
||||
Along with a backend listing for each service with a server set up for each pod.
|
||||
|
||||
If you edit your `/etc/hosts` again you should be able to access the cheese websites in your browser.
|
||||
|
||||
@@ -598,11 +609,11 @@ If you edit your `/etc/hosts` again you should be able to access the cheese webs
|
||||
echo "$(minikube ip) stilton.minikube cheddar.minikube wensleydale.minikube" | sudo tee -a /etc/hosts
|
||||
```
|
||||
|
||||
* [Stilton](http://stilton.minikube/)
|
||||
* [Cheddar](http://cheddar.minikube/)
|
||||
* [Wensleydale](http://wensleydale.minikube/)
|
||||
- [Stilton](http://stilton.minikube/)
|
||||
- [Cheddar](http://cheddar.minikube/)
|
||||
- [Wensleydale](http://wensleydale.minikube/)
|
||||
|
||||
## Path based routing
|
||||
## Path-based Routing
|
||||
|
||||
Now lets suppose that our fictional client has decided that while they are super happy about our cheesy web design, when they asked for 3 websites they had not really bargained on having to buy 3 domain names.
|
||||
|
||||
@@ -634,10 +645,11 @@ spec:
|
||||
serviceName: wensleydale
|
||||
servicePort: http
|
||||
```
|
||||
|
||||
[examples/k8s/cheeses-ingress.yaml](https://github.com/containous/traefik/tree/master/examples/k8s/cheeses-ingress.yaml)
|
||||
|
||||
!!! note
|
||||
we are configuring Træfik to strip the prefix from the url path with the `traefik.frontend.rule.type` annotation so that we can use the containers from the previous example without modification.
|
||||
We are configuring Træfik to strip the prefix from the url path with the `traefik.frontend.rule.type` annotation so that we can use the containers from the previous example without modification.
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/cheeses-ingress.yaml
|
||||
@@ -649,14 +661,14 @@ echo "$(minikube ip) cheeses.minikube" | sudo tee -a /etc/hosts
|
||||
|
||||
You should now be able to visit the websites in your browser.
|
||||
|
||||
* [cheeses.minikube/stilton](http://cheeses.minikube/stilton/)
|
||||
* [cheeses.minikube/cheddar](http://cheeses.minikube/cheddar/)
|
||||
* [cheeses.minikube/wensleydale](http://cheeses.minikube/wensleydale/)
|
||||
- [cheeses.minikube/stilton](http://cheeses.minikube/stilton/)
|
||||
- [cheeses.minikube/cheddar](http://cheeses.minikube/cheddar/)
|
||||
- [cheeses.minikube/wensleydale](http://cheeses.minikube/wensleydale/)
|
||||
|
||||
## Specifying priority for routing
|
||||
## Specifying Routing Priorities
|
||||
|
||||
Sometimes you need to specify priority for ingress route, especially when handling wildcard routes.
|
||||
This can be done by adding annotation `traefik.frontend.priority`, i.e.:
|
||||
Sometimes you need to specify priority for ingress routes, especially when handling wildcard routes.
|
||||
This can be done by adding the `traefik.frontend.priority` annotation, i.e.:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -691,34 +703,33 @@ spec:
|
||||
servicePort: http
|
||||
```
|
||||
|
||||
Note that priority values must be quoted to avoid them being interpreted as numbers (which are illegal for annotations).
|
||||
Note that priority values must be quoted to avoid numeric interpretation (which are illegal for annotations).
|
||||
|
||||
## Forwarding to ExternalNames
|
||||
|
||||
When specifying an [ExternalName](https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors),
|
||||
Træfik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
|
||||
Træfik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
|
||||
This still requires setting up a proper port mapping on the Service from the Ingress port to the (external) Service port.
|
||||
|
||||
## Disable passing the Host header
|
||||
## Disable passing the Host Header
|
||||
|
||||
By default Træfik will pass the incoming Host header on to the upstream resource.
|
||||
By default Træfik will pass the incoming Host header to the upstream resource.
|
||||
|
||||
There are times however where you may not want this to be the case.
|
||||
For example if your service is of the ExternalName type.
|
||||
However, there are times when you may not want this to be the case. For example, if your service is of the ExternalName type.
|
||||
|
||||
### Disable entirely
|
||||
### Disable globally
|
||||
|
||||
Add the following to your toml config:
|
||||
Add the following to your TOML configuration file:
|
||||
|
||||
```toml
|
||||
disablePassHostHeaders = true
|
||||
```
|
||||
|
||||
### Disable per ingress
|
||||
### Disable per Ingress
|
||||
|
||||
To disable passing the Host header per ingress resource set the `traefik.frontend.passHostHeader` annotation on your ingress to `false`.
|
||||
To disable passing the Host header per ingress resource set the `traefik.frontend.passHostHeader` annotation on your ingress to `"false"`.
|
||||
|
||||
Here is an example ingress definition:
|
||||
Here is an example definition:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -754,12 +765,11 @@ spec:
|
||||
externalName: static.otherdomain.com
|
||||
```
|
||||
|
||||
If you were to visit `example.com/static` the request would then be passed onto `static.otherdomain.com/static` and s`tatic.otherdomain.com` would receive the request with the Host header being `static.otherdomain.com`.
|
||||
If you were to visit `example.com/static` the request would then be passed on to `static.otherdomain.com/static`, and `static.otherdomain.com` would receive the request with the Host header being `static.otherdomain.com`.
|
||||
|
||||
!!! note
|
||||
The per ingress annotation overides whatever the global value is set to.
|
||||
So you could set `disablePassHostHeaders` to `true` in your toml file and then enable passing
|
||||
the host header per ingress if you wanted.
|
||||
The per-ingress annotation overrides whatever the global value is set to.
|
||||
So you could set `disablePassHostHeaders` to `true` in your TOML configuration file and then enable passing the host header per ingress if you wanted.
|
||||
|
||||
## Partitioning the Ingress object space
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Key-value store configuration
|
||||
|
||||
Both [static global configuration](/user-guide/kv-config/#static-configuration-in-key-value-store) and [dynamic](/user-guide/kv-config/#dynamic-configuration-in-key-value-store) configuration can be sorted in a Key-value store.
|
||||
Both [static global configuration](/user-guide/kv-config/#static-configuration-in-key-value-store) and [dynamic](/user-guide/kv-config/#dynamic-configuration-in-key-value-store) configuration can be stored in a Key-value store.
|
||||
|
||||
This section explains how to launch Træfik using a configuration loaded from a Key-value store.
|
||||
|
||||
@@ -70,10 +70,13 @@ logLevel = "DEBUG"
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
|
||||
[entryPoints.https.tls]
|
||||
[[entryPoints.https.tls.certificates]]
|
||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
||||
@@ -94,8 +97,8 @@ defaultEntryPoints = ["http", "https"]
|
||||
watch = true
|
||||
prefix = "traefik"
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
[api]
|
||||
entrypoint = "api"
|
||||
```
|
||||
|
||||
And there, the same global configuration in the Key-value Store (using `prefix = "traefik"`):
|
||||
@@ -105,17 +108,18 @@ And there, the same global configuration in the Key-value Store (using `prefix =
|
||||
| `/traefik/loglevel` | `DEBUG` |
|
||||
| `/traefik/defaultentrypoints/0` | `http` |
|
||||
| `/traefik/defaultentrypoints/1` | `https` |
|
||||
| `/traefik/entrypoints/api/address` | `:8081` |
|
||||
| `/traefik/entrypoints/http/address` | `:80` |
|
||||
| `/traefik/entrypoints/https/address` | `:443` |
|
||||
| `/traefik/entrypoints/https/tls/certificates/0/certfile` | `integration/fixtures/https/snitest.com.cert` |
|
||||
| `/traefik/entrypoints/https/tls/certificates/0/keyfile` | `integration/fixtures/https/snitest.com.key` |
|
||||
| `/traefik/entrypoints/https/tls/certificates/1/certfile` | `--BEGIN CERTIFICATE--<cert file content>--END CERTIFICATE--` |
|
||||
| `/traefik/entrypoints/https/tls/certificates/1/keyfile` | `--BEGIN CERTIFICATE--<key file content>--END CERTIFICATE--` |
|
||||
| `/traefik/entrypoints/other-https/address` | `:4443`
|
||||
| `/traefik/entrypoints/other-https/address` | `:4443` |
|
||||
| `/traefik/consul/endpoint` | `127.0.0.1:8500` |
|
||||
| `/traefik/consul/watch` | `true` |
|
||||
| `/traefik/consul/prefix` | `traefik` |
|
||||
| `/traefik/web/address` | `:8081` |
|
||||
| `/traefik/api/entrypoint` | `api` |
|
||||
|
||||
In case you are setting key values manually:
|
||||
|
||||
@@ -270,14 +274,14 @@ Here is the toml configuration we would like to store in the store :
|
||||
backend = "backend2"
|
||||
rule = "Path:/test"
|
||||
|
||||
[[tlsConfiguration]]
|
||||
[[tls]]
|
||||
entryPoints = ["https"]
|
||||
[tlsConfiguration.certificate]
|
||||
[tls.certificate]
|
||||
certFile = "path/to/your.cert"
|
||||
keyFile = "path/to/your.key"
|
||||
[[tlsConfiguration]]
|
||||
[[tls]]
|
||||
entryPoints = ["https","other-https"]
|
||||
[tlsConfiguration.certificate]
|
||||
[tls.certificate]
|
||||
certFile = """-----BEGIN CERTIFICATE-----
|
||||
<cert file content>
|
||||
-----END CERTIFICATE-----"""
|
||||
@@ -331,19 +335,20 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi
|
||||
|
||||
- certificate 1
|
||||
|
||||
| Key | Value |
|
||||
|----------------------------------------------------|--------------------|
|
||||
| `/traefik/tlsconfiguration/1/entrypoints` | `https` |
|
||||
| `/traefik/tlsconfiguration/1/certificate/certfile` | `path/to/your.cert`|
|
||||
| `/traefik/tlsconfiguration/1/certificate/keyfile` | `path/to/your.key` |
|
||||
| Key | Value |
|
||||
|---------------------------------------|--------------------|
|
||||
| `/traefik/tls/1/entrypoints` | `https` |
|
||||
| `/traefik/tls/1/certificate/certfile` | `path/to/your.cert`|
|
||||
| `/traefik/tls/1/certificate/keyfile` | `path/to/your.key` |
|
||||
|
||||
- certificate 2
|
||||
|
||||
| Key | Value |
|
||||
|----------------------------------------------------|-----------------------|
|
||||
| `/traefik/tlsconfiguration/2/entrypoints` | `https,other-https` |
|
||||
| `/traefik/tlsconfiguration/2/certificate/certfile` | `<cert file content>` |
|
||||
| `/traefik/tlsconfiguration/2/certificate/certfile` | `<key file content>` |
|
||||
| Key | Value |
|
||||
|---------------------------------------|-----------------------|
|
||||
| `/traefik/tls/2/entrypoints` | `https,other-https` |
|
||||
| `/traefik/tls/2/certificate/certfile` | `<cert file content>` |
|
||||
| `/traefik/tls/2/certificate/certfile` | `<key file content>` |
|
||||
|
||||
### Atomic configuration changes
|
||||
|
||||
Træfik can watch the backends/frontends configuration changes and generate its configuration automatically.
|
||||
@@ -378,9 +383,9 @@ Here, although the `/traefik_configurations/2/...` keys have been set, the old c
|
||||
| `/traefik_configurations/1/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
||||
| `/traefik_configurations/1/backends/backend1/servers/server1/weight` | `10` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
||||
|
||||
Once the `/traefik/alias` key is updated, the new `/traefik_configurations/2` configuration becomes active atomically.
|
||||
|
||||
@@ -392,9 +397,9 @@ Here, we have a 50% balance between the `http://172.17.0.3:80` and the `http://1
|
||||
| `/traefik_configurations/1/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
||||
| `/traefik_configurations/1/backends/backend1/servers/server1/weight` | `10` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/url` | `http://172.17.0.3:80` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server1/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/url` | `http://172.17.0.4:80` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
||||
| `/traefik_configurations/2/backends/backend1/servers/server2/weight` | `5` |
|
||||
|
||||
!!! note
|
||||
Træfik *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik/alias`.
|
||||
@@ -403,7 +408,7 @@ Here, we have a 50% balance between the `http://172.17.0.3:80` and the `http://1
|
||||
## Store configuration in Key-value store
|
||||
|
||||
!!! note
|
||||
Don't forget to [setup the connection between Træfik and Key-value store](/user-guide/kv-config/#launch-trfk).
|
||||
Don't forget to [setup the connection between Træfik and Key-value store](/user-guide/kv-config/#launch-trfik).
|
||||
|
||||
The static Træfik configuration in a key-value store can be automatically created and updated, using the [`storeconfig` subcommand](/basics/#commands).
|
||||
|
||||
@@ -411,7 +416,7 @@ The static Træfik configuration in a key-value store can be automatically creat
|
||||
traefik storeconfig [flags] ...
|
||||
```
|
||||
This command is here only to automate the [process which upload the configuration into the Key-value store](/user-guide/kv-config/#upload-the-configuration-in-the-key-value-store).
|
||||
Træfik will not start but the [static configuration](/basics/#static-trfk-configuration) will be uploaded into the Key-value store.
|
||||
Træfik will not start but the [static configuration](/basics/#static-trfik-configuration) will be uploaded into the Key-value store.
|
||||
|
||||
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
|
||||
|
||||
|
||||
@@ -28,6 +28,24 @@ Following is the order by which Traefik tries to identify the port (the first on
|
||||
1. The port from the application's `portDefinitions` field (possibly indexed through the `traefik.portIndex` label, otherwise the first one).
|
||||
1. The port from the application's `ipAddressPerTask` field (possibly indexed through the `traefik.portIndex` label, otherwise the first one).
|
||||
|
||||
## 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).
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
traefik.web.port=80
|
||||
```
|
||||
|
||||
```
|
||||
traefik.admin.port=8080
|
||||
```
|
||||
|
||||
(Note that the service names `web` and `admin` can be chosen arbitrarily.)
|
||||
|
||||
Technically, Traefik will create one pair of frontend and backend configurations for each service.
|
||||
|
||||
## Achieving high availability
|
||||
|
||||
### Scenarios
|
||||
|
||||
@@ -90,7 +90,7 @@ docker-machine ssh manager "docker service create \
|
||||
--docker.swarmmode \
|
||||
--docker.domain=traefik \
|
||||
--docker.watch \
|
||||
--web"
|
||||
--api"
|
||||
```
|
||||
|
||||
Let's explain this command:
|
||||
@@ -102,7 +102,7 @@ Let's explain this command:
|
||||
| `--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. |
|
||||
| `--web` | activate the webUI on port 8080 |
|
||||
| `--api | activate the webUI on port 8080 |
|
||||
|
||||
|
||||
## Deploy your apps
|
||||
|
||||
@@ -86,14 +86,14 @@ docker $(docker-machine config mhs-demo0) run \
|
||||
-c /dev/null \
|
||||
--docker \
|
||||
--docker.domain=traefik \
|
||||
--docker.endpoint=tcp://$(docker-machine ip mhs-demo0):3376 \
|
||||
--docker.endpoint=tcp://$(docker-machine ip mhs-demo0):2376 \
|
||||
--docker.tls \
|
||||
--docker.tls.ca=/ssl/ca.pem \
|
||||
--docker.tls.cert=/ssl/server.pem \
|
||||
--docker.tls.key=/ssl/server-key.pem \
|
||||
--docker.tls.insecureSkipVerify \
|
||||
--docker.watch \
|
||||
--web
|
||||
--api
|
||||
```
|
||||
|
||||
Let's explain this command:
|
||||
@@ -105,9 +105,9 @@ Let's explain this command:
|
||||
| `-v /var/lib/boot2docker/:/ssl` | mount the ssl keys generated by docker-machine |
|
||||
| `-c /dev/null` | empty config file |
|
||||
| `--docker` | enable docker backend |
|
||||
| `--docker.endpoint=tcp://172.18.0.1:3376` | connect to the swarm master using the docker_gwbridge network |
|
||||
| `--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 |
|
||||
| `--web` | activate the webUI on port 8080 |
|
||||
| `--api` | activate the webUI on port 8080 |
|
||||
|
||||
|
||||
## Deploy your apps
|
||||
|
||||
@@ -19,6 +19,8 @@ entryPoint = "https"
|
||||
onDemand = false
|
||||
OnHostRule = true
|
||||
caServer = "http://traefik.localhost.com:4000/directory"
|
||||
[acme.httpChallenge]
|
||||
entryPoint="http"
|
||||
|
||||
|
||||
[web]
|
||||
|
||||
@@ -29,6 +29,8 @@ services :
|
||||
- bhsm
|
||||
- bmysql
|
||||
- brabbitmq
|
||||
volumes:
|
||||
- "./rate-limit-policies.yml:/go/src/github.com/letsencrypt/boulder/test/rate-limit-policies.yml:ro"
|
||||
|
||||
bhsm:
|
||||
image: letsencrypt/boulder-tools:2016-11-02
|
||||
@@ -78,6 +80,7 @@ services :
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "5001:443" # Needed for SNI challenge
|
||||
- "5002:80" # Needed for HTTP challenge
|
||||
expose:
|
||||
- "8080"
|
||||
labels:
|
||||
|
||||
42
examples/acme/rate-limit-policies.yml
Normal file
42
examples/acme/rate-limit-policies.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
totalCertificates:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
certificatesPerName:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
ratelimit.me: 1
|
||||
lim.it: 0
|
||||
# Hostnames used by the letsencrypt client integration test.
|
||||
le.wtf: 10000
|
||||
le1.wtf: 10000
|
||||
le2.wtf: 10000
|
||||
le3.wtf: 10000
|
||||
nginx.wtf: 10000
|
||||
good-caa-reserved.com: 10000
|
||||
bad-caa-reserved.com: 10000
|
||||
ecdsa.le.wtf: 10000
|
||||
must-staple.le.wtf: 10000
|
||||
registrationOverrides:
|
||||
101: 1000
|
||||
registrationsPerIP:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
127.0.0.1: 1000000
|
||||
pendingAuthorizationsPerAccount:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
certificatesPerFQDNSet:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
le.wtf: 10000
|
||||
le1.wtf: 10000
|
||||
le2.wtf: 10000
|
||||
le3.wtf: 10000
|
||||
le.wtf,le1.wtf: 10000
|
||||
good-caa-reserved.com: 10000
|
||||
nginx.wtf: 10000
|
||||
ecdsa.le.wtf: 10000
|
||||
must-staple.le.wtf: 10000
|
||||
@@ -38,16 +38,7 @@ services:
|
||||
|
||||
etcdctl-ping:
|
||||
image: tenstartups/etcdctl
|
||||
command: --endpoints=[10.0.1.12:2379] get "traefik/acme/storagefile"
|
||||
environment:
|
||||
ETCDCTL_DIAL_: "TIMEOUT 10s"
|
||||
ETCDCTL_API : "3"
|
||||
networks:
|
||||
- net
|
||||
|
||||
etcdctl-rm:
|
||||
image: tenstartups/etcdctl
|
||||
command: --endpoints=[10.0.1.12:2379] del "/traefik/acme/storagefile"
|
||||
command: --endpoints=[10.0.1.12:2379] get "traefik/acme/storage"
|
||||
environment:
|
||||
ETCDCTL_DIAL_: "TIMEOUT 10s"
|
||||
ETCDCTL_API : "3"
|
||||
@@ -82,6 +73,8 @@ services:
|
||||
- bhsm
|
||||
- bmysql
|
||||
- brabbitmq
|
||||
volumes:
|
||||
- "./rate-limit-policies.yml:/go/src/github.com/letsencrypt/boulder/test/rate-limit-policies.yml:ro"
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.0.1.3
|
||||
@@ -129,7 +122,6 @@ services:
|
||||
image: containous/traefik
|
||||
volumes:
|
||||
- "./traefik.toml:/traefik.toml:ro"
|
||||
- "./acme.json:/acme.json:ro"
|
||||
command: storeconfig --debug
|
||||
networks:
|
||||
- net
|
||||
@@ -146,11 +138,13 @@ services:
|
||||
expose:
|
||||
- "443"
|
||||
- "5001"
|
||||
- "5002"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "8080:8080"
|
||||
- "443:443"
|
||||
- "5001:443" # Needed for SNI challenge
|
||||
- "5002:80" # Needed for HTTP challenge
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.0.1.8
|
||||
@@ -167,6 +161,7 @@ services:
|
||||
expose:
|
||||
- "443"
|
||||
- "5001"
|
||||
- "5002"
|
||||
ports:
|
||||
- "88:80"
|
||||
- "8888:8080"
|
||||
|
||||
@@ -32,15 +32,6 @@ delete_services() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Init the environment : get IP address and create needed files
|
||||
init_acme_json() {
|
||||
echo "CREATE empty acme.json file"
|
||||
rm -f $basedir/acme.json && \
|
||||
touch $basedir/acme.json && \
|
||||
echo "{}" > $basedir/acme.json && \
|
||||
chmod 600 $basedir/acme.json # Needed for ACME
|
||||
}
|
||||
|
||||
start_consul() {
|
||||
up_environment consul
|
||||
waiting_counter=12
|
||||
@@ -76,7 +67,6 @@ start_etcd3() {
|
||||
}
|
||||
|
||||
start_storeconfig_consul() {
|
||||
init_acme_json
|
||||
# Create traefik.toml with consul provider
|
||||
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
||||
echo '
|
||||
@@ -85,29 +75,13 @@ start_storeconfig_consul() {
|
||||
watch = true
|
||||
prefix = "traefik"' >> $basedir/traefik.toml
|
||||
up_environment traefik-storeconfig
|
||||
rm -f $basedir/traefik.toml && rm -f $basedir/acme.json
|
||||
# Delete acme-storage-file key
|
||||
rm -f $basedir/traefik.toml
|
||||
waiting_counter=5
|
||||
# Not start Traefik store config if consul is not started
|
||||
echo "Delete storage file key..."
|
||||
while [[ -z $(curl -s http://10.0.1.2:8500/v1/kv/traefik/acme/storagefile) && $waiting_counter -gt 0 ]]; do
|
||||
sleep 5
|
||||
let waiting_counter-=1
|
||||
done
|
||||
if [[ $waiting_counter -eq 0 ]]; then
|
||||
echo "[WARN] Unable to get storagefile key in consul"
|
||||
else
|
||||
curl -s --request DELETE http://10.0.1.2:8500/v1/kv/traefik/acme/storagefile
|
||||
ret=$1
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "[ERROR] Unable to delete storagefile key from consul kv."
|
||||
fi
|
||||
fi
|
||||
delete_services traefik-storeconfig
|
||||
|
||||
}
|
||||
|
||||
start_storeconfig_etcd3() {
|
||||
init_acme_json
|
||||
# Create traefik.toml with consul provider
|
||||
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
||||
echo '
|
||||
@@ -117,20 +91,15 @@ start_storeconfig_etcd3() {
|
||||
prefix = "/traefik"
|
||||
useAPIV3 = true' >> $basedir/traefik.toml
|
||||
up_environment traefik-storeconfig
|
||||
rm -f $basedir/traefik.toml && rm -f $basedir/acme.json
|
||||
# Delete acme-storage-file key
|
||||
rm -f $basedir/traefik.toml
|
||||
waiting_counter=5
|
||||
# Not start Traefik store config if consul is not started
|
||||
# Don't start Traefik store config if ETCD3 is not started
|
||||
echo "Delete storage file key..."
|
||||
while [[ $(docker-compose -f $doc_file up --exit-code-from etcdctl-ping etcdctl-ping &>/dev/null) -ne 0 && $waiting_counter -gt 0 ]]; do
|
||||
sleep 5
|
||||
let waiting_counter-=1
|
||||
done
|
||||
# Not start Traefik store config if consul is not started
|
||||
echo "Delete storage file key from ETCD3..."
|
||||
|
||||
up_environment etcdctl-rm && \
|
||||
delete_services etcdctl-rm traefik-storeconfig etcdctl-ping
|
||||
delete_services traefik-storeconfig etcdctl-ping
|
||||
}
|
||||
|
||||
start_traefik() {
|
||||
|
||||
42
examples/cluster/rate-limit-policies.yml
Normal file
42
examples/cluster/rate-limit-policies.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
totalCertificates:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
certificatesPerName:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
ratelimit.me: 1
|
||||
lim.it: 0
|
||||
# Hostnames used by the letsencrypt client integration test.
|
||||
le.wtf: 10000
|
||||
le1.wtf: 10000
|
||||
le2.wtf: 10000
|
||||
le3.wtf: 10000
|
||||
nginx.wtf: 10000
|
||||
good-caa-reserved.com: 10000
|
||||
bad-caa-reserved.com: 10000
|
||||
ecdsa.le.wtf: 10000
|
||||
must-staple.le.wtf: 10000
|
||||
registrationOverrides:
|
||||
101: 1000
|
||||
registrationsPerIP:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
127.0.0.1: 1000000
|
||||
pendingAuthorizationsPerAccount:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
certificatesPerFQDNSet:
|
||||
window: 1h
|
||||
threshold: 100000
|
||||
overrides:
|
||||
le.wtf: 10000
|
||||
le1.wtf: 10000
|
||||
le2.wtf: 10000
|
||||
le3.wtf: 10000
|
||||
le.wtf,le1.wtf: 10000
|
||||
good-caa-reserved.com: 10000
|
||||
nginx.wtf: 10000
|
||||
ecdsa.le.wtf: 10000
|
||||
must-staple.le.wtf: 10000
|
||||
@@ -12,14 +12,14 @@ defaultEntryPoints = ["http", "https"]
|
||||
[acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "traefik/acme/account"
|
||||
storageFile = "/acme.json"
|
||||
entryPoint = "https"
|
||||
OnHostRule = true
|
||||
caServer = "http://traefik.boulder.com:4000/directory"
|
||||
[acme.httpChallenge]
|
||||
entryPoint="http"
|
||||
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[docker]
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
|
||||
@@ -26,11 +26,11 @@ curl -i -H "Accept: application/json" -X PUT -d "Path:/test" ht
|
||||
|
||||
|
||||
# certificate 1
|
||||
curl -i -H "Accept: application/json" -X PUT -d "https" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair1/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test1.crt" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair1/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test1.key" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair1/certificate/keyfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "https" http://localhost:8500/v1/kv/traefik/tls/pair1/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test1.crt" http://localhost:8500/v1/kv/traefik/tls/pair1/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test1.key" http://localhost:8500/v1/kv/traefik/tls/pair1/certificate/keyfile
|
||||
|
||||
# certificate 2
|
||||
curl -i -H "Accept: application/json" -X PUT -d "http,https" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair2/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test2.crt" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair2/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test2.key" http://localhost:8500/v1/kv/traefik/tlsconfiguration/pair2/certificate/keyfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "http,https" http://localhost:8500/v1/kv/traefik/tls/pair2/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test2.crt" http://localhost:8500/v1/kv/traefik/tls/pair2/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d "/tmp/test2.key" http://localhost:8500/v1/kv/traefik/tls/pair2/certificate/keyfile
|
||||
|
||||
@@ -28,14 +28,14 @@ function insert_etcd2_data() {
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="Path:/test" http://localhost:2379/v2/keys/traefik/frontends/frontend2/routes/test_2/rule
|
||||
|
||||
# certificate 1
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="https" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair1/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test1.crt" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair1/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test1.key" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair1/certificate/keyfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="https" http://localhost:2379/v2/keys/traefik/tls/pair1/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test1.crt" http://localhost:2379/v2/keys/traefik/tls/pair1/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test1.key" http://localhost:2379/v2/keys/traefik/tls/pair1/certificate/keyfile
|
||||
|
||||
# certificate 2
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="http,https" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair2/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test2.crt" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair2/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test2.key" http://localhost:2379/v2/keys/traefik/tlsconfiguration/pair2/certificate/keyfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="http,https" http://localhost:2379/v2/keys/traefik/tls/pair2/entrypoints
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test2.crt" http://localhost:2379/v2/keys/traefik/tls/pair2/certificate/certfile
|
||||
curl -i -H "Accept: application/json" -X PUT -d value="/tmp/test2.key" http://localhost:2379/v2/keys/traefik/tls/pair2/certificate/keyfile
|
||||
}
|
||||
|
||||
#
|
||||
@@ -71,14 +71,14 @@ function insert_etcd3_data() {
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/frontends/frontend2/routes/test_2/rule" "Path:/test"
|
||||
|
||||
# certificate 1
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair1/entrypoints" "https"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair1/certificate/certfile" "/tmp/test1.crt"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair1/certificate/keyfile" "/tmp/test1.key"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair1/entrypoints" "https"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair1/certificate/certfile" "/tmp/test1.crt"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair1/certificate/keyfile" "/tmp/test1.key"
|
||||
|
||||
# certificate 2
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair2/entrypoints" "https"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair2/certificate/certfile" "/tmp/test2.crt"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tlsconfiguration/pair2/certificate/keyfile" "/tmp/test2.key"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair2/entrypoints" "https"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair2/certificate/certfile" "/tmp/test2.crt"
|
||||
docker container run --rm -ti -e ETCDCTL_DIAL_="TIMEOUT 10s" -e ETCDCTL_API="3" tenstartups/etcdctl --endpoints=[$etcd_ip:2379] put "/traefik/tls/pair2/certificate/keyfile" "/tmp/test2.key"
|
||||
}
|
||||
|
||||
function show_usage() {
|
||||
|
||||
860
glide.lock
generated
860
glide.lock
generated
@@ -1,860 +0,0 @@
|
||||
hash: 4595cac0a682ce8e36b78630f12a3cfab75307fc58cb4a1f5e416017d3ae20d6
|
||||
updated: 2017-11-30T10:34:41.246378337+01:00
|
||||
imports:
|
||||
- name: cloud.google.com/go
|
||||
version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c
|
||||
subpackages:
|
||||
- compute/metadata
|
||||
- internal
|
||||
- name: github.com/abbot/go-http-auth
|
||||
version: 0ddd408d5d60ea76e320503cc7dd091992dee608
|
||||
- name: github.com/aokoli/goutils
|
||||
version: 3391d3790d23d03408670993e957e8f408993c34
|
||||
- name: github.com/armon/go-proxyproto
|
||||
version: 48572f11356f1843b694f21a290d4f1006bc5e47
|
||||
- name: github.com/ArthurHlt/go-eureka-client
|
||||
version: 9d0a49cbd39aa3634ae1977e9f519a262b10adaf
|
||||
subpackages:
|
||||
- eureka
|
||||
- name: github.com/ArthurHlt/gominlog
|
||||
version: 72eebf980f467d3ab3a8b4ddf660f664911ce519
|
||||
- name: github.com/aws/aws-sdk-go
|
||||
version: 3f8f870ec9939e32b3372abf74d24e468bcd285d
|
||||
subpackages:
|
||||
- aws
|
||||
- aws/awserr
|
||||
- aws/awsutil
|
||||
- aws/client
|
||||
- aws/client/metadata
|
||||
- aws/corehandlers
|
||||
- aws/credentials
|
||||
- aws/credentials/ec2rolecreds
|
||||
- aws/credentials/endpointcreds
|
||||
- aws/credentials/stscreds
|
||||
- aws/defaults
|
||||
- aws/ec2metadata
|
||||
- aws/endpoints
|
||||
- aws/request
|
||||
- aws/session
|
||||
- aws/signer/v4
|
||||
- private/protocol
|
||||
- private/protocol/ec2query
|
||||
- private/protocol/json/jsonutil
|
||||
- private/protocol/jsonrpc
|
||||
- private/protocol/query
|
||||
- private/protocol/query/queryutil
|
||||
- private/protocol/rest
|
||||
- private/protocol/restxml
|
||||
- private/protocol/xml/xmlutil
|
||||
- private/waiter
|
||||
- service/dynamodb
|
||||
- service/dynamodb/dynamodbattribute
|
||||
- service/dynamodb/dynamodbiface
|
||||
- service/dynamodbattribute
|
||||
- service/ec2
|
||||
- service/ecs
|
||||
- service/route53
|
||||
- service/sts
|
||||
- name: github.com/Azure/azure-sdk-for-go
|
||||
version: f7bb4db3ea4c73dc58bd284c38ea644a79324be0
|
||||
subpackages:
|
||||
- arm/dns
|
||||
- name: github.com/Azure/go-autorest
|
||||
version: f6be1abbb5abd0517522f850dd785990d373da7e
|
||||
subpackages:
|
||||
- autorest
|
||||
- autorest/adal
|
||||
- autorest/azure
|
||||
- autorest/date
|
||||
- autorest/to
|
||||
- name: github.com/beorn7/perks
|
||||
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
subpackages:
|
||||
- quantile
|
||||
- name: github.com/blang/semver
|
||||
version: 31b736133b98f26d5e078ec9eb591666edfd091f
|
||||
- name: github.com/boltdb/bolt
|
||||
version: e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
||||
- name: github.com/BurntSushi/toml
|
||||
version: b26d9c308763d68093482582cea63d69be07a0f0
|
||||
- name: github.com/BurntSushi/ty
|
||||
version: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74
|
||||
subpackages:
|
||||
- fun
|
||||
- name: github.com/cenk/backoff
|
||||
version: 5d150e7eec023ce7a124856b37c68e54b4050ac7
|
||||
- name: github.com/codahale/hdrhistogram
|
||||
version: 9208b142303c12d8899bae836fd524ac9338b4fd
|
||||
- name: github.com/codegangsta/cli
|
||||
version: bf4a526f48af7badd25d2cb02d587e1b01be3b50
|
||||
- name: github.com/containous/flaeg
|
||||
version: 60c87a513a955ca7225e1b1c772581cea8420cb4
|
||||
- name: github.com/containous/mux
|
||||
version: 06ccd3e75091eb659b1d720cda0e16bc7057954c
|
||||
- name: github.com/containous/staert
|
||||
version: af517d5b70db9c4b0505e0144fcc62b054057d2a
|
||||
- name: github.com/containous/traefik-extra-service-fabric
|
||||
version: 8076098dbfe814cba9e895ecbd896f1896b6b2d5
|
||||
- name: github.com/coreos/bbolt
|
||||
version: 3c6cbfb299c11444eb2f8c9d48f0d2ce09157423
|
||||
- name: github.com/coreos/etcd
|
||||
version: f1d7dd87da3e8feab4aaf675b8e29c6a5ed5f58b
|
||||
subpackages:
|
||||
- auth/authpb
|
||||
- client
|
||||
- clientv3
|
||||
- clientv3/concurrency
|
||||
- etcdserver/api/v3rpc/rpctypes
|
||||
- etcdserver/etcdserverpb
|
||||
- mvcc/mvccpb
|
||||
- pkg/pathutil
|
||||
- pkg/srv
|
||||
- pkg/types
|
||||
- version
|
||||
- name: github.com/coreos/go-oidc
|
||||
version: 5644a2f50e2d2d5ba0b474bc5bc55fea1925936d
|
||||
subpackages:
|
||||
- http
|
||||
- jose
|
||||
- key
|
||||
- oauth2
|
||||
- oidc
|
||||
- name: github.com/coreos/go-semver
|
||||
version: 8ab6407b697782a06568d4b7f1db25550ec2e4c6
|
||||
subpackages:
|
||||
- semver
|
||||
- name: github.com/coreos/go-systemd
|
||||
version: 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||
subpackages:
|
||||
- daemon
|
||||
- name: github.com/coreos/pkg
|
||||
version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
|
||||
subpackages:
|
||||
- health
|
||||
- httputil
|
||||
- timeutil
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/decker502/dnspod-go
|
||||
version: f33a2c6040fc2550a631de7b3a53bddccdcd73fb
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: d2709f9f1f31ebcda9651b03077758c1f3a0018c
|
||||
- name: github.com/dnsimple/dnsimple-go
|
||||
version: f2d9b723cc9547d182e24ac2e527ae25d25fc93f
|
||||
subpackages:
|
||||
- dnsimple
|
||||
- name: github.com/docker/distribution
|
||||
version: b38e5838b7b2f2ad48e06ec4b500011976080621
|
||||
subpackages:
|
||||
- context
|
||||
- digestset
|
||||
- reference
|
||||
- registry/api/errcode
|
||||
- registry/api/v2
|
||||
- registry/client
|
||||
- registry/client/auth
|
||||
- registry/client/auth/challenge
|
||||
- registry/client/transport
|
||||
- registry/storage/cache
|
||||
- registry/storage/cache/memory
|
||||
- uuid
|
||||
- name: github.com/docker/docker
|
||||
version: 75c7536d2e2e328b644bf69153de879d1d197988
|
||||
subpackages:
|
||||
- api
|
||||
- api/types
|
||||
- api/types/blkiodev
|
||||
- api/types/container
|
||||
- api/types/events
|
||||
- api/types/filters
|
||||
- api/types/image
|
||||
- api/types/mount
|
||||
- api/types/network
|
||||
- api/types/registry
|
||||
- api/types/strslice
|
||||
- api/types/swarm
|
||||
- api/types/time
|
||||
- api/types/versions
|
||||
- api/types/volume
|
||||
- builder/dockerignore
|
||||
- client
|
||||
- opts
|
||||
- pkg/archive
|
||||
- pkg/fileutils
|
||||
- pkg/gitutils
|
||||
- pkg/homedir
|
||||
- pkg/httputils
|
||||
- pkg/idtools
|
||||
- pkg/ioutils
|
||||
- pkg/jsonlog
|
||||
- pkg/jsonmessage
|
||||
- pkg/longpath
|
||||
- pkg/mount
|
||||
- pkg/namesgenerator
|
||||
- pkg/pools
|
||||
- pkg/progress
|
||||
- pkg/promise
|
||||
- pkg/random
|
||||
- pkg/stdcopy
|
||||
- pkg/streamformatter
|
||||
- pkg/stringid
|
||||
- pkg/symlink
|
||||
- pkg/system
|
||||
- pkg/tarsum
|
||||
- pkg/term
|
||||
- pkg/term/windows
|
||||
- pkg/tlsconfig
|
||||
- pkg/urlutil
|
||||
- registry
|
||||
- runconfig/opts
|
||||
- name: github.com/docker/go-connections
|
||||
version: e15c02316c12de00874640cd76311849de2aeed5
|
||||
subpackages:
|
||||
- nat
|
||||
- sockets
|
||||
- tlsconfig
|
||||
- name: github.com/docker/go-units
|
||||
version: 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||
- name: github.com/docker/leadership
|
||||
version: af20da7d3e62be9259835e93261acf931b5adecf
|
||||
repo: https://github.com/containous/leadership.git
|
||||
vcs: git
|
||||
- name: github.com/docker/libkv
|
||||
version: 5e4bb288a9a74320bb03f5c18d6bdbab0d8049de
|
||||
repo: https://github.com/abronan/libkv.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- store
|
||||
- store/boltdb
|
||||
- store/consul
|
||||
- store/etcd
|
||||
- store/etcd/v2
|
||||
- store/etcd/v3
|
||||
- store/zookeeper
|
||||
- name: github.com/docker/libtrust
|
||||
version: 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||
- name: github.com/donovanhide/eventsource
|
||||
version: b8f31a59085e69dd2678cf51840db2ac625cb741
|
||||
- name: github.com/eapache/channels
|
||||
version: 47238d5aae8c0fefd518ef2bee46290909cf8263
|
||||
- name: github.com/eapache/queue
|
||||
version: 44cc805cf13205b55f69e14bcb69867d1ae92f98
|
||||
- name: github.com/edeckers/auroradnsclient
|
||||
version: 398f53855ba258191157e20fabfaccca5e13cea9
|
||||
subpackages:
|
||||
- records
|
||||
- requests
|
||||
- requests/errors
|
||||
- tokens
|
||||
- zones
|
||||
- name: github.com/elazarl/go-bindata-assetfs
|
||||
version: 30f82fa23fd844bd5bb1e5f216db87fd77b5eb43
|
||||
- name: github.com/emicklei/go-restful
|
||||
version: 89ef8af493ab468a45a42bb0d89a06fccdd2fb22
|
||||
subpackages:
|
||||
- log
|
||||
- swagger
|
||||
- name: github.com/exoscale/egoscale
|
||||
version: 325740036187ddae3a5b74be00fbbc70011c4d96
|
||||
- name: github.com/fatih/color
|
||||
version: 62e9147c64a1ed519147b62a56a14e83e2be02c1
|
||||
- name: github.com/gambol99/go-marathon
|
||||
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
|
||||
- name: github.com/ghodss/yaml
|
||||
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
||||
- name: github.com/go-ini/ini
|
||||
version: f384f410798cbe7cdce40eec40b79ed32bb4f1ad
|
||||
- name: github.com/go-kit/kit
|
||||
version: f66b0e13579bfc5a48b9e2a94b1209c107ea1f41
|
||||
subpackages:
|
||||
- log
|
||||
- metrics
|
||||
- metrics/dogstatsd
|
||||
- metrics/generic
|
||||
- metrics/influx
|
||||
- metrics/internal/lv
|
||||
- metrics/internal/ratemap
|
||||
- metrics/multi
|
||||
- metrics/prometheus
|
||||
- metrics/statsd
|
||||
- util/conn
|
||||
- name: github.com/go-logfmt/logfmt
|
||||
version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5
|
||||
- name: github.com/go-openapi/jsonpointer
|
||||
version: 46af16f9f7b149af66e5d1bd010e3574dc06de98
|
||||
- name: github.com/go-openapi/jsonreference
|
||||
version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
|
||||
- name: github.com/go-openapi/spec
|
||||
version: 6aced65f8501fe1217321abf0749d354824ba2ff
|
||||
- name: github.com/go-openapi/swag
|
||||
version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72
|
||||
- name: github.com/go-stack/stack
|
||||
version: 54be5f394ed2c3e19dac9134a40a95ba5a017f7b
|
||||
- name: github.com/gogo/protobuf
|
||||
version: 909568be09de550ed094403c2bf8a261b5bb730a
|
||||
subpackages:
|
||||
- proto
|
||||
- sortkeys
|
||||
- name: github.com/golang/glog
|
||||
version: 44145f04b68cf362d9c4df2182967c2275eaefed
|
||||
- name: github.com/golang/protobuf
|
||||
version: 4bd1920723d7b7c925de087aa32e2187708897f7
|
||||
subpackages:
|
||||
- jsonpb
|
||||
- proto
|
||||
- ptypes/any
|
||||
- name: github.com/google/go-github
|
||||
version: fe7d11f8add400587b6718d9f39a62e42cb04c28
|
||||
subpackages:
|
||||
- github
|
||||
- name: github.com/google/go-querystring
|
||||
version: 53e6ce116135b80d037921a7fdd5138cf32d7a8a
|
||||
subpackages:
|
||||
- query
|
||||
- name: github.com/google/gofuzz
|
||||
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5
|
||||
- name: github.com/googleapis/gax-go
|
||||
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
|
||||
- name: github.com/gorilla/context
|
||||
version: 215affda49addc4c8ef7e2534915df2c8c35c6cd
|
||||
- name: github.com/gorilla/websocket
|
||||
version: a69d9f6de432e2c6b296a947d8a5ee88f68522cf
|
||||
- name: github.com/hashicorp/consul
|
||||
version: 3f92cc70e8163df866873c16c6d89889b5c95fc4
|
||||
subpackages:
|
||||
- api
|
||||
- name: github.com/hashicorp/go-cleanhttp
|
||||
version: 3573b8b52aa7b37b9358d966a898feb387f62437
|
||||
- name: github.com/hashicorp/go-version
|
||||
version: 03c5bf6be031b6dd45afec16b1cf94fc8938bc77
|
||||
- name: github.com/hashicorp/serf
|
||||
version: 19f2c401e122352c047a84d6584dd51e2fb8fcc4
|
||||
subpackages:
|
||||
- coordinate
|
||||
- name: github.com/huandu/xstrings
|
||||
version: 3959339b333561bf62a38b424fd41517c2c90f40
|
||||
- name: github.com/imdario/mergo
|
||||
version: 7fe0c75c13abdee74b09fcacef5ea1c6bba6a874
|
||||
- name: github.com/influxdata/influxdb
|
||||
version: 2d474a3089bcfce6b472779be9470a1f0ef3d5e4
|
||||
subpackages:
|
||||
- client/v2
|
||||
- models
|
||||
- pkg/escape
|
||||
- name: github.com/JamesClonk/vultr
|
||||
version: 2fd0705ce648e602e6c9c57329a174270a4f6688
|
||||
subpackages:
|
||||
- lib
|
||||
- name: github.com/jjcollinge/servicefabric
|
||||
version: 93a44e59fc887cda489913c6fc5bda834989f3bd
|
||||
- name: github.com/jmespath/go-jmespath
|
||||
version: bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||
- name: github.com/jonboulle/clockwork
|
||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
||||
- name: github.com/juju/ratelimit
|
||||
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
|
||||
- name: github.com/kr/logfmt
|
||||
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
|
||||
- name: github.com/mailgun/minheap
|
||||
version: 7c28d80e2ada649fc8ab1a37b86d30a2633bd47c
|
||||
- name: github.com/mailgun/timetools
|
||||
version: 7e6055773c5137efbeb3bd2410d705fe10ab6bfd
|
||||
- name: github.com/mailgun/ttlmap
|
||||
version: c1c17f74874f2a5ea48bfb06b5459d4ef2689749
|
||||
- name: github.com/mailru/easyjson
|
||||
version: d5b7844b561a7bc640052f1b935f7b800330d7e0
|
||||
subpackages:
|
||||
- buffer
|
||||
- jlexer
|
||||
- jwriter
|
||||
- name: github.com/Masterminds/semver
|
||||
version: 59c29afe1a994eacb71c833025ca7acf874bb1da
|
||||
- name: github.com/Masterminds/sprig
|
||||
version: e039e20e500c2c025d9145be375e27cf42a94174
|
||||
- name: github.com/mattn/go-colorable
|
||||
version: 5411d3eea5978e6cdc258b30de592b60df6aba96
|
||||
repo: https://github.com/mattn/go-colorable
|
||||
- name: github.com/mattn/go-isatty
|
||||
version: 57fdcb988a5c543893cc61bce354a6e24ab70022
|
||||
repo: https://github.com/mattn/go-isatty
|
||||
- name: github.com/mattn/go-shellwords
|
||||
version: 02e3cf038dcea8290e44424da473dd12be796a8a
|
||||
- name: github.com/matttproud/golang_protobuf_extensions
|
||||
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||
subpackages:
|
||||
- pbutil
|
||||
- name: github.com/mesos/mesos-go
|
||||
version: 068d5470506e3780189fe607af40892814197c5e
|
||||
subpackages:
|
||||
- detector
|
||||
- detector/zoo
|
||||
- mesos
|
||||
- mesosproto
|
||||
- mesosutil
|
||||
- upid
|
||||
- name: github.com/mesosphere/mesos-dns
|
||||
version: b47dc4c19f215e98da687b15b4c64e70f629bea5
|
||||
repo: https://github.com/containous/mesos-dns.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- detect
|
||||
- errorutil
|
||||
- logging
|
||||
- models
|
||||
- records
|
||||
- records/labels
|
||||
- records/state
|
||||
- util
|
||||
- name: github.com/Microsoft/go-winio
|
||||
version: f533f7a102197536779ea3a8cb881d639e21ec5a
|
||||
- name: github.com/miekg/dns
|
||||
version: 8060d9f51305bbe024b99679454e62f552cd0b0b
|
||||
- name: github.com/mitchellh/copystructure
|
||||
version: d23ffcb85de31694d6ccaa23ccb4a03e55c1303f
|
||||
- name: github.com/mitchellh/hashstructure
|
||||
version: 2bca23e0e452137f789efbc8610126fd8b94f73b
|
||||
- name: github.com/mitchellh/mapstructure
|
||||
version: d0303fe809921458f417bcf828397a65db30a7e4
|
||||
- name: github.com/mitchellh/reflectwalk
|
||||
version: 63d60e9d0dbc60cf9164e6510889b0db6683d98c
|
||||
- name: github.com/mvdan/xurls
|
||||
version: db96455566f05ffe42bd6ac671f05eeb1152b45d
|
||||
- name: github.com/Nvveen/Gotty
|
||||
version: 6018b68f96b839edfbe3fb48668853f5dbad88a3
|
||||
repo: https://github.com/ijc25/Gotty.git
|
||||
vcs: git
|
||||
- name: github.com/NYTimes/gziphandler
|
||||
version: d6f46609c7629af3a02d791a4666866eed3cbd3e
|
||||
- name: github.com/ogier/pflag
|
||||
version: 45c278ab3607870051a2ea9040bb85fcb8557481
|
||||
- name: github.com/opencontainers/go-digest
|
||||
version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
||||
- name: github.com/opencontainers/image-spec
|
||||
version: f03dbe35d449c54915d235f1a3cf8f585a24babe
|
||||
subpackages:
|
||||
- specs-go
|
||||
- specs-go/v1
|
||||
- name: github.com/ovh/go-ovh
|
||||
version: 4b1fea467323b74c5f462f0947f402b428ca0626
|
||||
subpackages:
|
||||
- ovh
|
||||
- name: github.com/pborman/uuid
|
||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
||||
- name: github.com/pkg/errors
|
||||
version: c605e284fe17294bda444b34710735b29d1a9d90
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/prometheus/client_golang
|
||||
version: 08fd2e12372a66e68e30523c7642e0cbc3e4fbde
|
||||
subpackages:
|
||||
- prometheus
|
||||
- prometheus/promhttp
|
||||
- name: github.com/prometheus/client_model
|
||||
version: 6f3806018612930941127f2a7c6c453ba2c527d2
|
||||
subpackages:
|
||||
- go
|
||||
- name: github.com/prometheus/common
|
||||
version: 49fee292b27bfff7f354ee0f64e1bc4850462edf
|
||||
subpackages:
|
||||
- expfmt
|
||||
- internal/bitbucket.org/ww/goautoneg
|
||||
- model
|
||||
- name: github.com/prometheus/procfs
|
||||
version: a1dba9ce8baed984a2495b658c82687f8157b98f
|
||||
subpackages:
|
||||
- xfs
|
||||
- name: github.com/PuerkitoBio/purell
|
||||
version: 8a290539e2e8629dbc4e6bad948158f790ec31f4
|
||||
- name: github.com/PuerkitoBio/urlesc
|
||||
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
|
||||
- name: github.com/rancher/go-rancher
|
||||
version: 52e2f489534007ae843065468c5a1920d542afa4
|
||||
subpackages:
|
||||
- v2
|
||||
- name: github.com/rancher/go-rancher-metadata
|
||||
version: d2103caca5873119ff423d29cba09b4d03cd69b8
|
||||
subpackages:
|
||||
- metadata
|
||||
- name: github.com/ryanuber/go-glob
|
||||
version: 256dc444b735e061061cf46c809487313d5b0065
|
||||
- name: github.com/samuel/go-zookeeper
|
||||
version: 1d7be4effb13d2d908342d349d71a284a7542693
|
||||
subpackages:
|
||||
- zk
|
||||
- name: github.com/satori/go.uuid
|
||||
version: 879c5887cd475cd7864858769793b2ceb0d44feb
|
||||
- name: github.com/Sirupsen/logrus
|
||||
version: 10f801ebc38b33738c9d17d50860f484a0988ff5
|
||||
- name: github.com/spf13/pflag
|
||||
version: cb88ea77998c3f024757528e3305022ab50b43be
|
||||
- name: github.com/stretchr/objx
|
||||
version: cbeaeb16a013161a98496fad62933b1d21786672
|
||||
- name: github.com/stretchr/testify
|
||||
version: 4d4bfba8f1d1027c4fdbe371823030df51419987
|
||||
subpackages:
|
||||
- assert
|
||||
- mock
|
||||
- require
|
||||
- name: github.com/thoas/stats
|
||||
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||
- name: github.com/timewasted/linode
|
||||
version: 37e84520dcf74488f67654f9c775b9752c232dc1
|
||||
subpackages:
|
||||
- dns
|
||||
- name: github.com/tv42/zbase32
|
||||
version: 03389da7e0bf9844767f82690f4d68fc097a1306
|
||||
- name: github.com/ugorji/go
|
||||
version: ea9cd21fa0bc41ee4bdd50ac7ed8cbc7ea2ed960
|
||||
subpackages:
|
||||
- codec
|
||||
- name: github.com/unrolled/render
|
||||
version: 50716a0a853771bb36bfce61a45cdefdb98c2e6e
|
||||
- name: github.com/unrolled/secure
|
||||
version: 824e85271811af89640ea25620c67f6c2eed987e
|
||||
- name: github.com/urfave/negroni
|
||||
version: 490e6a555d47ca891a89a150d0c1ef3922dfffe9
|
||||
- name: github.com/VividCortex/gohistogram
|
||||
version: 51564d9861991fb0ad0f531c99ef602d0f9866e6
|
||||
- name: github.com/vulcand/oxy
|
||||
version: 7b6e758ab449705195df638765c4ca472248908a
|
||||
repo: https://github.com/containous/oxy.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- cbreaker
|
||||
- connlimit
|
||||
- forward
|
||||
- memmetrics
|
||||
- ratelimit
|
||||
- roundrobin
|
||||
- stream
|
||||
- utils
|
||||
- name: github.com/vulcand/predicate
|
||||
version: 19b9dde14240d94c804ae5736ad0e1de10bf8fe6
|
||||
- name: github.com/vulcand/route
|
||||
version: cb89d787ddbb1c5849a7ac9f79004c1fd12a4a32
|
||||
- name: github.com/vulcand/vulcand
|
||||
version: 42492a3a85e294bdbdd1bcabb8c12769a81ea284
|
||||
subpackages:
|
||||
- conntracker
|
||||
- plugin
|
||||
- plugin/rewrite
|
||||
- router
|
||||
- name: github.com/xenolf/lego
|
||||
version: 67c86d860a797ce2483f50d9174d4ed24984bef2
|
||||
subpackages:
|
||||
- acme
|
||||
- providers/dns
|
||||
- providers/dns/auroradns
|
||||
- providers/dns/azure
|
||||
- providers/dns/cloudflare
|
||||
- providers/dns/digitalocean
|
||||
- providers/dns/dnsimple
|
||||
- providers/dns/dnsmadeeasy
|
||||
- providers/dns/dnspod
|
||||
- providers/dns/dyn
|
||||
- providers/dns/exoscale
|
||||
- providers/dns/gandi
|
||||
- providers/dns/googlecloud
|
||||
- providers/dns/linode
|
||||
- providers/dns/namecheap
|
||||
- providers/dns/ns1
|
||||
- providers/dns/otc
|
||||
- providers/dns/ovh
|
||||
- providers/dns/pdns
|
||||
- providers/dns/rackspace
|
||||
- providers/dns/rfc2136
|
||||
- providers/dns/route53
|
||||
- providers/dns/vultr
|
||||
- name: golang.org/x/crypto
|
||||
version: 4ed45ec682102c643324fae5dff8dab085b6c300
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- blowfish
|
||||
- ocsp
|
||||
- pbkdf2
|
||||
- scrypt
|
||||
- name: golang.org/x/net
|
||||
version: c8c74377599bd978aee1cf3b9b63a8634051cec2
|
||||
subpackages:
|
||||
- context
|
||||
- context/ctxhttp
|
||||
- http2
|
||||
- http2/hpack
|
||||
- idna
|
||||
- internal/timeseries
|
||||
- lex/httplex
|
||||
- proxy
|
||||
- publicsuffix
|
||||
- trace
|
||||
- websocket
|
||||
- name: golang.org/x/oauth2
|
||||
version: 7fdf09982454086d5570c7db3e11f360194830ca
|
||||
subpackages:
|
||||
- google
|
||||
- internal
|
||||
- jws
|
||||
- jwt
|
||||
- name: golang.org/x/sys
|
||||
version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
||||
subpackages:
|
||||
- unix
|
||||
- windows
|
||||
- name: golang.org/x/text
|
||||
version: 4ee4af566555f5fbe026368b75596286a312663a
|
||||
subpackages:
|
||||
- cases
|
||||
- internal
|
||||
- internal/tag
|
||||
- language
|
||||
- runes
|
||||
- secure/bidirule
|
||||
- secure/precis
|
||||
- transform
|
||||
- unicode/bidi
|
||||
- unicode/norm
|
||||
- width
|
||||
- name: golang.org/x/time
|
||||
version: 8be79e1e0910c292df4e79c241bb7e8f7e725959
|
||||
subpackages:
|
||||
- rate
|
||||
- name: google.golang.org/api
|
||||
version: 1575df15c1bb8b18ad4d9bc5ca495cc85b0764fe
|
||||
subpackages:
|
||||
- dns/v1
|
||||
- gensupport
|
||||
- googleapi
|
||||
- googleapi/internal/uritemplates
|
||||
- name: google.golang.org/appengine
|
||||
version: 4f7eeb5305a4ba1966344836ba4af9996b7b4e05
|
||||
subpackages:
|
||||
- internal
|
||||
- internal/app_identity
|
||||
- internal/base
|
||||
- internal/datastore
|
||||
- internal/log
|
||||
- internal/modules
|
||||
- internal/remote_api
|
||||
- internal/urlfetch
|
||||
- urlfetch
|
||||
- name: google.golang.org/genproto
|
||||
version: 09f6ed296fc66555a25fe4ce95173148778dfa85
|
||||
subpackages:
|
||||
- googleapis/rpc/status
|
||||
- name: google.golang.org/grpc
|
||||
version: b3ddf786825de56a4178401b7e174ee332173b66
|
||||
subpackages:
|
||||
- codes
|
||||
- connectivity
|
||||
- credentials
|
||||
- grpclb/grpc_lb_v1
|
||||
- grpclog
|
||||
- internal
|
||||
- keepalive
|
||||
- metadata
|
||||
- naming
|
||||
- peer
|
||||
- stats
|
||||
- status
|
||||
- tap
|
||||
- transport
|
||||
- name: gopkg.in/fsnotify.v1
|
||||
version: 629574ca2a5df945712d3079857300b5e4da0236
|
||||
- name: gopkg.in/inf.v0
|
||||
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||
- name: gopkg.in/ini.v1
|
||||
version: 5b3e00af70a9484542169a976dcab8d03e601a17
|
||||
- name: gopkg.in/ns1/ns1-go.v2
|
||||
version: c563826f4cbef9c11bebeb9f20a3f7afe9c1e2f4
|
||||
subpackages:
|
||||
- rest
|
||||
- rest/model/account
|
||||
- rest/model/data
|
||||
- rest/model/dns
|
||||
- rest/model/filter
|
||||
- rest/model/monitor
|
||||
- name: gopkg.in/square/go-jose.v1
|
||||
version: aa2e30fdd1fe9dd3394119af66451ae790d50e0d
|
||||
subpackages:
|
||||
- cipher
|
||||
- json
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
|
||||
- name: k8s.io/client-go
|
||||
version: e121606b0d09b2e1c467183ee46217fa85a6b672
|
||||
subpackages:
|
||||
- discovery
|
||||
- kubernetes
|
||||
- kubernetes/typed/apps/v1beta1
|
||||
- kubernetes/typed/authentication/v1beta1
|
||||
- kubernetes/typed/authorization/v1beta1
|
||||
- kubernetes/typed/autoscaling/v1
|
||||
- kubernetes/typed/batch/v1
|
||||
- kubernetes/typed/batch/v2alpha1
|
||||
- kubernetes/typed/certificates/v1alpha1
|
||||
- kubernetes/typed/core/v1
|
||||
- kubernetes/typed/extensions/v1beta1
|
||||
- kubernetes/typed/policy/v1beta1
|
||||
- kubernetes/typed/rbac/v1alpha1
|
||||
- kubernetes/typed/storage/v1beta1
|
||||
- pkg/api
|
||||
- pkg/api/errors
|
||||
- pkg/api/install
|
||||
- pkg/api/meta
|
||||
- pkg/api/meta/metatypes
|
||||
- pkg/api/resource
|
||||
- pkg/api/unversioned
|
||||
- pkg/api/v1
|
||||
- pkg/api/validation/path
|
||||
- pkg/apimachinery
|
||||
- pkg/apimachinery/announced
|
||||
- pkg/apimachinery/registered
|
||||
- pkg/apis/apps
|
||||
- pkg/apis/apps/install
|
||||
- pkg/apis/apps/v1beta1
|
||||
- pkg/apis/authentication
|
||||
- pkg/apis/authentication/install
|
||||
- pkg/apis/authentication/v1beta1
|
||||
- pkg/apis/authorization
|
||||
- pkg/apis/authorization/install
|
||||
- pkg/apis/authorization/v1beta1
|
||||
- pkg/apis/autoscaling
|
||||
- pkg/apis/autoscaling/install
|
||||
- pkg/apis/autoscaling/v1
|
||||
- pkg/apis/batch
|
||||
- pkg/apis/batch/install
|
||||
- pkg/apis/batch/v1
|
||||
- pkg/apis/batch/v2alpha1
|
||||
- pkg/apis/certificates
|
||||
- pkg/apis/certificates/install
|
||||
- pkg/apis/certificates/v1alpha1
|
||||
- pkg/apis/extensions
|
||||
- pkg/apis/extensions/install
|
||||
- pkg/apis/extensions/v1beta1
|
||||
- pkg/apis/policy
|
||||
- pkg/apis/policy/install
|
||||
- pkg/apis/policy/v1beta1
|
||||
- pkg/apis/rbac
|
||||
- pkg/apis/rbac/install
|
||||
- pkg/apis/rbac/v1alpha1
|
||||
- pkg/apis/storage
|
||||
- pkg/apis/storage/install
|
||||
- pkg/apis/storage/v1beta1
|
||||
- pkg/auth/user
|
||||
- pkg/conversion
|
||||
- pkg/conversion/queryparams
|
||||
- pkg/fields
|
||||
- pkg/genericapiserver/openapi/common
|
||||
- pkg/labels
|
||||
- pkg/runtime
|
||||
- pkg/runtime/serializer
|
||||
- pkg/runtime/serializer/json
|
||||
- pkg/runtime/serializer/protobuf
|
||||
- pkg/runtime/serializer/recognizer
|
||||
- pkg/runtime/serializer/streaming
|
||||
- pkg/runtime/serializer/versioning
|
||||
- pkg/selection
|
||||
- pkg/third_party/forked/golang/reflect
|
||||
- pkg/third_party/forked/golang/template
|
||||
- pkg/types
|
||||
- pkg/util
|
||||
- pkg/util/cert
|
||||
- pkg/util/clock
|
||||
- pkg/util/diff
|
||||
- pkg/util/errors
|
||||
- pkg/util/flowcontrol
|
||||
- pkg/util/framer
|
||||
- pkg/util/integer
|
||||
- pkg/util/intstr
|
||||
- pkg/util/json
|
||||
- pkg/util/jsonpath
|
||||
- pkg/util/labels
|
||||
- pkg/util/net
|
||||
- pkg/util/parsers
|
||||
- pkg/util/rand
|
||||
- pkg/util/runtime
|
||||
- pkg/util/sets
|
||||
- pkg/util/uuid
|
||||
- pkg/util/validation
|
||||
- pkg/util/validation/field
|
||||
- pkg/util/wait
|
||||
- pkg/util/yaml
|
||||
- pkg/version
|
||||
- pkg/watch
|
||||
- pkg/watch/versioned
|
||||
- plugin/pkg/client/auth
|
||||
- plugin/pkg/client/auth/gcp
|
||||
- plugin/pkg/client/auth/oidc
|
||||
- rest
|
||||
- tools/cache
|
||||
- tools/clientcmd/api
|
||||
- tools/metrics
|
||||
- transport
|
||||
testImports:
|
||||
- name: github.com/Azure/go-ansiterm
|
||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
subpackages:
|
||||
- winterm
|
||||
- name: github.com/docker/cli
|
||||
version: d95fd2f38cfc23e077530c6181330727d561b6a0
|
||||
subpackages:
|
||||
- cli/command/image/build
|
||||
- cli/config
|
||||
- cli/config/configfile
|
||||
- name: github.com/docker/libcompose
|
||||
version: 1b708aac26a4fc6f9bff31728a8e3a252ef57dbd
|
||||
subpackages:
|
||||
- config
|
||||
- docker
|
||||
- docker/auth
|
||||
- docker/builder
|
||||
- docker/client
|
||||
- docker/container
|
||||
- docker/ctx
|
||||
- docker/image
|
||||
- docker/network
|
||||
- docker/service
|
||||
- docker/volume
|
||||
- labels
|
||||
- logger
|
||||
- lookup
|
||||
- project
|
||||
- project/events
|
||||
- project/options
|
||||
- utils
|
||||
- version
|
||||
- yaml
|
||||
- name: github.com/flynn/go-shlex
|
||||
version: 3f9db97f856818214da2e1057f8ad84803971cff
|
||||
- name: github.com/go-check/check
|
||||
version: ca0bf163426aa183d03fd4949101785c0347f273
|
||||
repo: https://github.com/containous/check.git
|
||||
vcs: git
|
||||
- name: github.com/gorilla/mux
|
||||
version: e444e69cbd2e2e3e0749a2f3c717cec491552bbf
|
||||
- name: github.com/libkermit/compose
|
||||
version: 4a33a16f1446ba205c4da7b09105d5bdc293b432
|
||||
subpackages:
|
||||
- check
|
||||
- name: github.com/libkermit/docker
|
||||
version: ddede409294e8c5ae66d68ac09edb6b27e8f3e4a
|
||||
- name: github.com/libkermit/docker-check
|
||||
version: e0695005d6819191cf8969b479c94c40c8d22aa4
|
||||
- name: github.com/opencontainers/runc
|
||||
version: b6b70e53451794e8333e9b602cc096b47a20bd0f
|
||||
subpackages:
|
||||
- libcontainer/system
|
||||
- libcontainer/user
|
||||
- name: github.com/stvp/go-udp-testing
|
||||
version: c4434f09ec131ecf30f986d5dcb1636508bfa49a
|
||||
- name: github.com/vdemeester/shakers
|
||||
version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
|
||||
- name: github.com/xeipuuv/gojsonpointer
|
||||
version: 6fe8760cad3569743d51ddbb243b26f8456742dc
|
||||
- name: github.com/xeipuuv/gojsonreference
|
||||
version: e02fc20de94c78484cd5ffb007f8af96be030a45
|
||||
- name: github.com/xeipuuv/gojsonschema
|
||||
version: 0c8571ac0ce161a5feb57375a9cdf148c98c0f70
|
||||
240
glide.yaml
240
glide.yaml
@@ -1,240 +0,0 @@
|
||||
package: github.com/containous/traefik
|
||||
ignore:
|
||||
- github.com/sirupsen/logrus
|
||||
import:
|
||||
- package: github.com/BurntSushi/toml
|
||||
version: v0.3.0
|
||||
- package: github.com/BurntSushi/ty
|
||||
subpackages:
|
||||
- fun
|
||||
- package: github.com/Sirupsen/logrus
|
||||
version: 10f801ebc38b33738c9d17d50860f484a0988ff5
|
||||
- package: github.com/cenk/backoff
|
||||
- package: github.com/containous/flaeg
|
||||
- package: github.com/containous/traefik-extra-service-fabric
|
||||
version: ^v1.0.1
|
||||
- package: github.com/vulcand/oxy
|
||||
version: 7b6e758ab449705195df638765c4ca472248908a
|
||||
repo: https://github.com/containous/oxy.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- cbreaker
|
||||
- connlimit
|
||||
- forward
|
||||
- roundrobin
|
||||
- stream
|
||||
- utils
|
||||
- ratelimit
|
||||
- package: github.com/urfave/negroni
|
||||
version: 490e6a555d47ca891a89a150d0c1ef3922dfffe9
|
||||
- package: github.com/containous/staert
|
||||
version: ^v2.0.0
|
||||
- package: github.com/docker/docker
|
||||
version: 75c7536d2e2e328b644bf69153de879d1d197988
|
||||
- package: github.com/docker/go-connections
|
||||
version: e15c02316c12de00874640cd76311849de2aeed5
|
||||
subpackages:
|
||||
- sockets
|
||||
- tlsconfig
|
||||
- package: github.com/docker/go-units
|
||||
version: 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||
- package: github.com/coreos/etcd
|
||||
version: v3.2.9
|
||||
- package: github.com/docker/libkv
|
||||
repo: https://github.com/abronan/libkv.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- store
|
||||
- store/boltdb
|
||||
- store/consul
|
||||
- store/etcd/v2
|
||||
- store/etcd/v3
|
||||
- store/zookeeper
|
||||
- package: github.com/elazarl/go-bindata-assetfs
|
||||
- package: github.com/containous/mux
|
||||
- package: github.com/hashicorp/consul
|
||||
subpackages:
|
||||
- api
|
||||
- package: github.com/thoas/stats
|
||||
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||
- package: github.com/unrolled/render
|
||||
- package: github.com/vulcand/vulcand
|
||||
version: 42492a3a85e294bdbdd1bcabb8c12769a81ea284
|
||||
subpackages:
|
||||
- plugin/rewrite
|
||||
- package: github.com/vulcand/predicate
|
||||
version: 19b9dde14240d94c804ae5736ad0e1de10bf8fe6
|
||||
- package: github.com/xenolf/lego
|
||||
version: 67c86d860a797ce2483f50d9174d4ed24984bef2
|
||||
subpackages:
|
||||
- acme
|
||||
- package: gopkg.in/fsnotify.v1
|
||||
- package: github.com/mattn/go-shellwords
|
||||
- package: github.com/ryanuber/go-glob
|
||||
- package: github.com/mesos/mesos-go
|
||||
subpackages:
|
||||
- mesosproto
|
||||
- mesos
|
||||
- upid
|
||||
- mesosutil
|
||||
- detector
|
||||
- package: github.com/miekg/dns
|
||||
version: 8060d9f51305bbe024b99679454e62f552cd0b0b
|
||||
- package: github.com/mesosphere/mesos-dns
|
||||
version: b47dc4c19f215e98da687b15b4c64e70f629bea5
|
||||
repo: https://github.com/containous/mesos-dns.git
|
||||
vcs: git
|
||||
- package: github.com/abbot/go-http-auth
|
||||
- package: github.com/NYTimes/gziphandler
|
||||
- package: github.com/docker/leadership
|
||||
repo: https://github.com/containous/leadership.git
|
||||
vcs: git
|
||||
- package: github.com/satori/go.uuid
|
||||
version: ^1.1.0
|
||||
- package: k8s.io/client-go
|
||||
version: v2.0.0
|
||||
- package: github.com/influxdata/influxdb
|
||||
version: v1.3.7
|
||||
subpackages:
|
||||
- client/v2
|
||||
- package: github.com/gambol99/go-marathon
|
||||
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
|
||||
- package: github.com/ArthurHlt/go-eureka-client
|
||||
subpackages:
|
||||
- eureka
|
||||
- package: github.com/coreos/go-systemd
|
||||
version: v14
|
||||
subpackages:
|
||||
- daemon
|
||||
- package: github.com/google/go-github
|
||||
- package: github.com/hashicorp/go-version
|
||||
- package: github.com/mvdan/xurls
|
||||
- package: github.com/go-kit/kit
|
||||
version: v0.3.0
|
||||
subpackages:
|
||||
- log
|
||||
- metrics
|
||||
- metrics/dogstatsd
|
||||
- metrics/internal/lv
|
||||
- metrics/internal/ratemap
|
||||
- metrics/multi
|
||||
- metrics/prometheus
|
||||
- metrics/statsd
|
||||
- util/conn
|
||||
- metrics/influx
|
||||
- package: github.com/prometheus/client_golang
|
||||
version: 08fd2e12372a66e68e30523c7642e0cbc3e4fbde
|
||||
subpackages:
|
||||
- prometheus
|
||||
- package: github.com/prometheus/common
|
||||
version: 49fee292b27bfff7f354ee0f64e1bc4850462edf
|
||||
- package: github.com/prometheus/client_model
|
||||
version: 6f3806018612930941127f2a7c6c453ba2c527d2
|
||||
- package: github.com/prometheus/procfs
|
||||
version: a1dba9ce8baed984a2495b658c82687f8157b98f
|
||||
- package: github.com/matttproud/golang_protobuf_extensions
|
||||
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||
- package: github.com/eapache/channels
|
||||
version: v1.1.0
|
||||
- package: golang.org/x/sys
|
||||
version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
||||
- package: golang.org/x/net
|
||||
version: c8c74377599bd978aee1cf3b9b63a8634051cec2
|
||||
subpackages:
|
||||
- http2
|
||||
- context
|
||||
- websocket
|
||||
- package: github.com/docker/distribution
|
||||
version: b38e5838b7b2f2ad48e06ec4b500011976080621
|
||||
- package: github.com/opencontainers/go-digest
|
||||
version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
||||
- package: github.com/opencontainers/image-spec
|
||||
version: f03dbe35d449c54915d235f1a3cf8f585a24babe
|
||||
subpackages:
|
||||
- specs-go
|
||||
- specs-go/v1
|
||||
- package: github.com/docker/libtrust
|
||||
version: 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||
- package: github.com/aws/aws-sdk-go
|
||||
version: v1.6.18
|
||||
subpackages:
|
||||
- aws
|
||||
- aws/credentials
|
||||
- aws/defaults
|
||||
- aws/ec2metadata
|
||||
- aws/endpoints
|
||||
- aws/request
|
||||
- aws/session
|
||||
- service/dynamodb
|
||||
- service/dynamodb/dynamodbiface
|
||||
- service/dynamodbattribute
|
||||
- service/ec2
|
||||
- service/ecs
|
||||
- package: cloud.google.com/go
|
||||
version: v0.7.0
|
||||
subpackages:
|
||||
- compute/metadata
|
||||
- package: github.com/gogo/protobuf
|
||||
version: v0.3
|
||||
subpackages:
|
||||
- proto
|
||||
- package: github.com/golang/protobuf
|
||||
version: 4bd1920723d7b7c925de087aa32e2187708897f7
|
||||
- package: github.com/rancher/go-rancher
|
||||
version: 52e2f489534007ae843065468c5a1920d542afa4
|
||||
- package: golang.org/x/oauth2
|
||||
version: 7fdf09982454086d5570c7db3e11f360194830ca
|
||||
subpackages:
|
||||
- google
|
||||
- package: golang.org/x/time
|
||||
version: 8be79e1e0910c292df4e79c241bb7e8f7e725959
|
||||
- package: github.com/rancher/go-rancher-metadata
|
||||
version: d2103caca5873119ff423d29cba09b4d03cd69b8
|
||||
- package: github.com/googleapis/gax-go
|
||||
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
|
||||
- package: google.golang.org/grpc
|
||||
version: v1.5.2
|
||||
- package: github.com/unrolled/secure
|
||||
version: 824e85271811af89640ea25620c67f6c2eed987e
|
||||
- package: github.com/Nvveen/Gotty
|
||||
version: 6018b68f96b839edfbe3fb48668853f5dbad88a3
|
||||
repo: https://github.com/ijc25/Gotty.git
|
||||
vcs: git
|
||||
- package: github.com/spf13/pflag
|
||||
version: cb88ea77998c3f024757528e3305022ab50b43be
|
||||
- package: github.com/stretchr/testify
|
||||
version: 4d4bfba8f1d1027c4fdbe371823030df51419987
|
||||
subpackages:
|
||||
- assert
|
||||
- mock
|
||||
- require
|
||||
- package: github.com/davecgh/go-spew
|
||||
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
|
||||
subpackages:
|
||||
- spew
|
||||
- package: github.com/Masterminds/sprig
|
||||
version: e039e20e500c2c025d9145be375e27cf42a94174
|
||||
- package: github.com/armon/go-proxyproto
|
||||
version: 48572f11356f1843b694f21a290d4f1006bc5e47
|
||||
- package: github.com/mitchellh/copystructure
|
||||
- package: github.com/mitchellh/hashstructure
|
||||
testImport:
|
||||
- package: github.com/stvp/go-udp-testing
|
||||
- package: github.com/docker/libcompose
|
||||
version: 1b708aac26a4fc6f9bff31728a8e3a252ef57dbd
|
||||
- package: github.com/go-check/check
|
||||
version: fork-containous
|
||||
repo: https://github.com/containous/check.git
|
||||
vcs: git
|
||||
- package: github.com/libkermit/compose
|
||||
version: 4a33a16f1446ba205c4da7b09105d5bdc293b432
|
||||
subpackages:
|
||||
- check
|
||||
- package: github.com/libkermit/docker
|
||||
version: ddede409294e8c5ae66d68ac09edb6b27e8f3e4a
|
||||
- package: github.com/libkermit/docker-check
|
||||
version: e0695005d6819191cf8969b479c94c40c8d22aa4
|
||||
- package: github.com/mattn/go-shellwords
|
||||
- package: github.com/vdemeester/shakers
|
||||
- package: github.com/docker/cli
|
||||
version: d95fd2f38cfc23e077530c6181330727d561b6a0
|
||||
@@ -48,6 +48,7 @@ type BackendHealthCheck struct {
|
||||
|
||||
//HealthCheck struct
|
||||
type HealthCheck struct {
|
||||
mutex sync.Mutex
|
||||
Backends map[string]*BackendHealthCheck
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
@@ -75,14 +76,16 @@ func NewBackendHealthCheck(options Options) *BackendHealthCheck {
|
||||
|
||||
//SetBackendsConfiguration set backends configuration
|
||||
func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendHealthCheck) {
|
||||
hc.mutex.Lock()
|
||||
hc.Backends = backends
|
||||
if hc.cancel != nil {
|
||||
hc.cancel()
|
||||
}
|
||||
ctx, cancel := context.WithCancel(parentCtx)
|
||||
hc.cancel = cancel
|
||||
hc.mutex.Unlock()
|
||||
|
||||
for backendID, backend := range hc.Backends {
|
||||
for backendID, backend := range backends {
|
||||
currentBackendID := backendID
|
||||
currentBackend := backend
|
||||
safe.Go(func() {
|
||||
|
||||
@@ -72,6 +72,36 @@ func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificate(c *check.C) {
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test OnDemand option with none provided certificate and challenge HTTP-01
|
||||
func (s *AcmeSuite) TestOnDemandRetrieveAcmeCertificateHTTP01(c *check.C) {
|
||||
testCase := AcmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme_http01.toml",
|
||||
onDemand: true,
|
||||
domainToCheck: acmeDomain}
|
||||
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test OnHostRule option with none provided certificate and challenge HTTP-01
|
||||
func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificateHTTP01(c *check.C) {
|
||||
testCase := AcmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme_http01.toml",
|
||||
onDemand: false,
|
||||
domainToCheck: acmeDomain}
|
||||
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test OnHostRule option with none provided certificate and challenge HTTP-01 and web path
|
||||
func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificateHTTP01WithPath(c *check.C) {
|
||||
testCase := AcmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme_http01_web.toml",
|
||||
onDemand: false,
|
||||
domainToCheck: acmeDomain}
|
||||
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test OnDemand option with a wildcard provided certificate
|
||||
func (s *AcmeSuite) TestOnDemandRetrieveAcmeCertificateWithWildcard(c *check.C) {
|
||||
testCase := AcmeTestCase{
|
||||
@@ -112,6 +142,19 @@ func (s *AcmeSuite) TestOnHostRuleRetrieveAcmeCertificateWithDynamicWildcard(c *
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test Let's encrypt down
|
||||
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
cmd, display := s.traefikCmd(withConfigFile("fixtures/acme/wrong_acme.toml"))
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// Expected traefik works
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// Doing an HTTPS request and test the response certificate
|
||||
func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase AcmeTestCase) {
|
||||
file := s.adaptFile(c, testCase.traefikConfFilePath, struct {
|
||||
|
||||
@@ -336,3 +336,53 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
|
||||
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
cmd, output := s.traefikCmd("--defaultEntryPoints=http", "--entryPoints=Name:http Address::8000", "--web", "--web.metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--docker", "--debug")
|
||||
defer output(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
|
||||
|
||||
s.createComposeProject(c, "base")
|
||||
s.composeProject.Start(c)
|
||||
ipWhoami01 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||
ipWhoami02 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||
file := s.adaptFile(c, "fixtures/multiple_provider.toml", struct{ IP string }{
|
||||
IP: ipWhoami02,
|
||||
})
|
||||
defer os.Remove(file)
|
||||
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||
defer output(c)
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.BodyContains(ipWhoami01))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8000/file", 1*time.Second, try.BodyContains(ipWhoami02))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
}
|
||||
|
||||
@@ -91,11 +91,11 @@ func (s *ConstraintSuite) TestMatchConstraintGlobal(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -117,11 +117,11 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintGlobal(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -143,11 +143,11 @@ func (s *ConstraintSuite) TestMatchConstraintProvider(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -169,11 +169,11 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintProvider(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -196,11 +196,11 @@ func (s *ConstraintSuite) TestMatchMultipleConstraint(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=eu-1"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=eu-1"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -223,11 +223,11 @@ func (s *ConstraintSuite) TestDoesNotMatchMultipleConstraint(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx")
|
||||
whoami := s.composeProject.Container(c, "whoami")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=us-1"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=us-1"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
@@ -145,9 +145,9 @@ func (s *ConsulCatalogSuite) TestSingleService(c *check.C) {
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
@@ -157,7 +157,7 @@ func (s *ConsulCatalogSuite) TestSingleService(c *check.C) {
|
||||
err = try.Request(req, 10*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
err = try.Request(req, 10*time.Second, try.StatusCodeIs(http.StatusNotFound), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
@@ -175,11 +175,11 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultFalseSingleService(c *check.C)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -201,16 +201,16 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultFalseSimpleServiceMultipleNode(
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
nginx2 := s.composeProject.Container(c, "nginx2")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
whoami2 := s.composeProject.Container(c, "whoami2")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"traefik.enable=true"})
|
||||
err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"traefik.enable=true"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -232,16 +232,16 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultTrueSimpleServiceMultipleNode(c
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
nginx2 := s.composeProject.Container(c, "nginx2")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
whoami2 := s.composeProject.Container(c, "whoami2")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"})
|
||||
err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -250,7 +250,7 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultTrueSimpleServiceMultipleNode(c
|
||||
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
}
|
||||
@@ -267,16 +267,16 @@ func (s *ConsulCatalogSuite) TestRefreshConfigWithMultipleNodeWithoutHealthCheck
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
nginx2 := s.composeProject.Container(c, "nginx2")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
whoami2 := s.composeProject.Container(c, "whoami2")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
err = s.registerAgentService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"})
|
||||
err = s.registerAgentService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering agent service"))
|
||||
defer s.deregisterAgentService(nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterAgentService(whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -285,25 +285,25 @@ func (s *ConsulCatalogSuite) TestRefreshConfigWithMultipleNodeWithoutHealthCheck
|
||||
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"})
|
||||
err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
s.deregisterService("test", nginx2.NetworkSettings.IPAddress)
|
||||
s.deregisterService("test", whoami2.NetworkSettings.IPAddress)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"})
|
||||
err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
}
|
||||
@@ -320,13 +320,13 @@ func (s *ConsulCatalogSuite) TestBasicAuthSimpleService(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{
|
||||
"traefik.frontend.auth.basic=test:$2a$06$O5NksJPAcgrC9MuANkSoE.Xe9DSg7KcLLFYNr1Lj6hPcMmvgwxhme,test2:$2y$10$xP1SZ70QbZ4K2bTGKJOhpujkpcLxQcB3kEPF6XAV19IdcqsZTyDEe",
|
||||
})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -357,16 +357,16 @@ func (s *ConsulCatalogSuite) TestRefreshConfigTagChange(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=false", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=false", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("nginx1"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=true", "traefik.backend.circuitbreaker=ResponseCodeRatio(500, 600, 0, 600) > 0.5"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true", "traefik.backend.circuitbreaker=ResponseCodeRatio(500, 600, 0, 600) > 0.5"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
@@ -376,7 +376,7 @@ func (s *ConsulCatalogSuite) TestRefreshConfigTagChange(c *check.C) {
|
||||
err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
@@ -397,19 +397,19 @@ func (s *ConsulCatalogSuite) TestCircuitBreaker(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
nginx2 := s.composeProject.Container(c, "nginx2")
|
||||
nginx3 := s.composeProject.Container(c, "nginx3")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
whoami2 := s.composeProject.Container(c, "whoami2")
|
||||
whoami3 := s.composeProject.Container(c, "whoami3")
|
||||
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
|
||||
err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 42, []string{"name=nginx2", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 42, []string{"name=whoami2", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress)
|
||||
err = s.registerService("test", nginx3.NetworkSettings.IPAddress, 42, []string{"name=nginx3", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress)
|
||||
err = s.registerService("test", whoami3.NetworkSettings.IPAddress, 42, []string{"name=whoami3", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
defer s.deregisterService("test", nginx3.NetworkSettings.IPAddress)
|
||||
defer s.deregisterService("test", whoami3.NetworkSettings.IPAddress)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -419,6 +419,46 @@ func (s *ConsulCatalogSuite) TestCircuitBreaker(c *check.C) {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TestRefreshConfigPortChange(c *check.C) {
|
||||
cmd, display := s.traefikCmd(
|
||||
withConfigFile("fixtures/consul_catalog/simple.toml"),
|
||||
"--consulCatalog",
|
||||
"--consulCatalog.exposedByDefault=false",
|
||||
"--consulCatalog.watch=true",
|
||||
"--consulCatalog.endpoint="+s.consulIP+":8500",
|
||||
"--consulCatalog.domain=consul.localhost")
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 81, []string{"name=whoami1", "traefik.enable=true"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
req.Host = "test.consul.localhost"
|
||||
|
||||
err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusBadGateway))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true"})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
defer s.deregisterService("test", whoami.NetworkSettings.IPAddress)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TestRetryWithConsulServer(c *check.C) {
|
||||
//Scale consul to 0 to be able to start traefik before and test retry
|
||||
s.composeProject.Scale(c, "consul", 0)
|
||||
@@ -451,9 +491,9 @@ func (s *ConsulCatalogSuite) TestRetryWithConsulServer(c *check.C) {
|
||||
s.composeProject.Scale(c, "consul", 1)
|
||||
s.waitToElectConsulLeader()
|
||||
|
||||
nginx := s.composeProject.Container(c, "nginx1")
|
||||
whoami := s.composeProject.Container(c, "whoami1")
|
||||
// Register service
|
||||
err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{})
|
||||
err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
|
||||
|
||||
// Provider consul catalog should be present
|
||||
|
||||
@@ -294,7 +294,10 @@ func (s *ConsulSuite) skipTestGlobalConfigurationWithClientTLS(c *check.C) {
|
||||
s.setupConsulTLS(c)
|
||||
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
|
||||
|
||||
err := s.kv.Put("traefik/web/address", []byte(":8081"), nil)
|
||||
err := s.kv.Put("traefik/api/entrypoint", []byte("api"), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = s.kv.Put("traefik/entrypoints/api/address", []byte(":8081"), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// wait for consul
|
||||
@@ -341,7 +344,7 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
||||
"/traefik/loglevel": "DEBUG",
|
||||
"/traefik/defaultentrypoints/0": "http",
|
||||
"/traefik/entrypoints/http/address": ":8000",
|
||||
"/traefik/web/address": ":8080",
|
||||
"/traefik/api/entrypoint": "traefik",
|
||||
"/traefik/consul/endpoint": consulHost + ":8500",
|
||||
}
|
||||
|
||||
@@ -561,15 +564,15 @@ func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
}
|
||||
|
||||
tlsconfigure1 := map[string]string{
|
||||
"traefik/tlsconfiguration/snitestcom/entrypoints": "https",
|
||||
"traefik/tlsconfiguration/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"traefik/tlsconfiguration/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
"traefik/tls/snitestcom/entrypoints": "https",
|
||||
"traefik/tls/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"traefik/tls/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
}
|
||||
|
||||
tlsconfigure2 := map[string]string{
|
||||
"traefik/tlsconfiguration/snitestorg/entrypoints": "https",
|
||||
"traefik/tlsconfiguration/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"traefik/tlsconfiguration/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
"traefik/tls/snitestorg/entrypoints": "https",
|
||||
"traefik/tls/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"traefik/tls/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
}
|
||||
|
||||
// config backends,frontends and first tls keypair
|
||||
@@ -610,7 +613,7 @@ func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for consul
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("traefik/tlsconfiguration/snitestcom/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("traefik/tls/snitestcom/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -639,7 +642,7 @@ func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for consul
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("traefik/tlsconfiguration/snitestorg/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("traefik/tls/snitestorg/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/docker/docker/pkg/namesgenerator"
|
||||
"github.com/go-check/check"
|
||||
d "github.com/libkermit/docker"
|
||||
docker "github.com/libkermit/docker-check"
|
||||
"github.com/libkermit/docker-check"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
@@ -25,8 +25,8 @@ var (
|
||||
// Images to have or pull before the build in order to make it work
|
||||
// FIXME handle this offline but loading them before build
|
||||
RequiredImages = map[string]string{
|
||||
"swarm": "1.0.0",
|
||||
"nginx": "1",
|
||||
"swarm": "1.0.0",
|
||||
"emilevauge/whoami": "latest",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ func (s *Etcd3Suite) TestCommandStoreConfig(c *check.C) {
|
||||
"/traefik/loglevel": "DEBUG",
|
||||
"/traefik/defaultentrypoints/0": "http",
|
||||
"/traefik/entrypoints/http/address": ":8000",
|
||||
"/traefik/web/address": ":8080",
|
||||
"/traefik/api/entrypoint": "traefik",
|
||||
"/traefik/etcd/endpoint": ipEtcd + ":4001",
|
||||
}
|
||||
|
||||
@@ -474,15 +474,15 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
}
|
||||
|
||||
tlsconfigure1 := map[string]string{
|
||||
"/traefik/tlsconfiguration/snitestcom/entrypoints": "https",
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
"/traefik/tls/snitestcom/entrypoints": "https",
|
||||
"/traefik/tls/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tls/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
}
|
||||
|
||||
tlsconfigure2 := map[string]string{
|
||||
"/traefik/tlsconfiguration/snitestorg/entrypoints": "https",
|
||||
"/traefik/tlsconfiguration/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"/traefik/tlsconfiguration/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
"/traefik/tls/snitestorg/entrypoints": "https",
|
||||
"/traefik/tls/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"/traefik/tls/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
}
|
||||
|
||||
// config backends,frontends and first tls keypair
|
||||
@@ -523,7 +523,7 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tlsconfiguration/snitestcom/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("/traefik/tls/snitestcom/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -557,7 +557,7 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tlsconfiguration/snitestorg/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("/traefik/tls/snitestorg/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -573,6 +573,113 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
req.Header.Set("Host", tr2.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
cn = resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "snitest.org")
|
||||
}
|
||||
|
||||
func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) {
|
||||
// start Træfik
|
||||
cmd, display := s.traefikCmd(
|
||||
withConfigFile("fixtures/etcd/simple_https.toml"),
|
||||
"--etcd",
|
||||
"--etcd.endpoint="+ipEtcd+":4001",
|
||||
"--etcd.useAPIV3=true")
|
||||
defer display(c)
|
||||
|
||||
// prepare to config
|
||||
snitestComCert, err := ioutil.ReadFile("fixtures/https/snitest.com.cert")
|
||||
c.Assert(err, checker.IsNil)
|
||||
snitestComKey, err := ioutil.ReadFile("fixtures/https/snitest.com.key")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend1 := map[string]string{
|
||||
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
|
||||
"/traefik/backends/backend1/servers/server1/url": "http://" + ipWhoami01 + ":80",
|
||||
"/traefik/backends/backend1/servers/server1/weight": "1",
|
||||
"/traefik/backends/backend1/servers/server2/url": "http://" + ipWhoami02 + ":80",
|
||||
"/traefik/backends/backend1/servers/server2/weight": "1",
|
||||
}
|
||||
|
||||
frontend1 := map[string]string{
|
||||
"/traefik/frontends/frontend1/backend": "backend1",
|
||||
"/traefik/frontends/frontend1/entrypoints": "https",
|
||||
"/traefik/frontends/frontend1/priority": "1",
|
||||
"/traefik/frontends/frontend1/routes/test_1/rule": "Host:snitest.com",
|
||||
}
|
||||
|
||||
tlsconfigure1 := map[string]string{
|
||||
"/traefik/tls/snitestcom/entrypoints": "https",
|
||||
"/traefik/tls/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tls/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
}
|
||||
|
||||
// config backends,frontends and first tls keypair
|
||||
for key, value := range backend1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range frontend1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range tlsconfigure1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
tr1 := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.com",
|
||||
},
|
||||
}
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tls/snitestcom/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// wait for Træfik
|
||||
err = try.GetRequest(traefikWebEtcdURL+"api/providers", 60*time.Second, try.BodyContains(string("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h")))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
client := &http.Client{Transport: tr1}
|
||||
req.Host = tr1.TLSClientConfig.ServerName
|
||||
req.Header.Set("Host", tr1.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
var resp *http.Response
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
cn := resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "snitest.com")
|
||||
|
||||
// now we delete the tls cert/key pairs,so the endpoint show use default cert/key pair
|
||||
for key := range tlsconfigure1 {
|
||||
err := s.kv.Delete(key)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// waiting for Træfik to pull configuration
|
||||
err = try.GetRequest(traefikWebEtcdURL+"api/providers", 30*time.Second, try.BodyNotContains("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
client = &http.Client{Transport: tr1}
|
||||
req.Host = tr1.TLSClientConfig.ServerName
|
||||
req.Header.Set("Host", tr1.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
cn = resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "TRAEFIK DEFAULT CERT")
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ func (s *EtcdSuite) TestCommandStoreConfig(c *check.C) {
|
||||
"/traefik/loglevel": "DEBUG",
|
||||
"/traefik/defaultentrypoints/0": "http",
|
||||
"/traefik/entrypoints/http/address": ":8000",
|
||||
"/traefik/web/address": ":8080",
|
||||
"/traefik/api/entrypoint": "traefik",
|
||||
"/traefik/etcd/endpoint": etcdHost + ":4001",
|
||||
}
|
||||
|
||||
@@ -490,15 +490,15 @@ func (s *EtcdSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
}
|
||||
|
||||
tlsconfigure1 := map[string]string{
|
||||
"/traefik/tlsconfiguration/snitestcom/entrypoints": "https",
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
"/traefik/tls/snitestcom/entrypoints": "https",
|
||||
"/traefik/tls/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tls/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
}
|
||||
|
||||
tlsconfigure2 := map[string]string{
|
||||
"/traefik/tlsconfiguration/snitestorg/entrypoints": "https",
|
||||
"/traefik/tlsconfiguration/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"/traefik/tlsconfiguration/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
"/traefik/tls/snitestorg/entrypoints": "https",
|
||||
"/traefik/tls/snitestorg/certificate/keyfile": string(snitestOrgKey),
|
||||
"/traefik/tls/snitestorg/certificate/certfile": string(snitestOrgCert),
|
||||
}
|
||||
|
||||
// config backends,frontends and first tls keypair
|
||||
@@ -539,7 +539,7 @@ func (s *EtcdSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tlsconfiguration/snitestcom/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("/traefik/tls/snitestcom/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
@@ -573,7 +573,7 @@ func (s *EtcdSuite) TestSNIDynamicTlsConfig(c *check.C) {
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tlsconfiguration/snitestorg/certificate/keyfile", nil)
|
||||
_, err := s.kv.Get("/traefik/tls/snitestorg/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
@@ -8,14 +8,16 @@ defaultEntryPoints = ["http"]
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
[entryPoints.api]
|
||||
address = ":7888"
|
||||
|
||||
checkNewVersion = false
|
||||
|
||||
################################################################
|
||||
# Web configuration backend
|
||||
# Api configuration
|
||||
################################################################
|
||||
[web]
|
||||
address = ":7888"
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
|
||||
################################################################
|
||||
# File configuration backend
|
||||
|
||||
35
integration/fixtures/acme/acme_http01.toml
Normal file
35
integration/fixtures/acme/acme_http01.toml
Normal file
@@ -0,0 +1,35 @@
|
||||
logLevel = "DEBUG"
|
||||
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":5002"
|
||||
[entryPoints.https]
|
||||
address = ":5001"
|
||||
[entryPoints.https.tls]
|
||||
|
||||
|
||||
[acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "/dev/null"
|
||||
entryPoint = "https"
|
||||
onDemand = {{.OnDemand}}
|
||||
OnHostRule = {{.OnHostRule}}
|
||||
caServer = "http://{{.BoulderHost}}:4000/directory"
|
||||
[acme.httpchallenge]
|
||||
entrypoint="http"
|
||||
|
||||
[file]
|
||||
|
||||
[backends]
|
||||
[backends.backend]
|
||||
[backends.backend.servers.server1]
|
||||
url = "http://127.0.0.1:9010"
|
||||
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend]
|
||||
backend = "backend"
|
||||
[frontends.frontend.routes.test]
|
||||
rule = "Host:traefik.acme.wtf"
|
||||
38
integration/fixtures/acme/acme_http01_web.toml
Normal file
38
integration/fixtures/acme/acme_http01_web.toml
Normal file
@@ -0,0 +1,38 @@
|
||||
logLevel = "DEBUG"
|
||||
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":5002"
|
||||
[entryPoints.https]
|
||||
address = ":5001"
|
||||
[entryPoints.https.tls]
|
||||
|
||||
|
||||
[web]
|
||||
path="/traefik"
|
||||
|
||||
[acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "/dev/null"
|
||||
entryPoint = "https"
|
||||
onDemand = {{.OnDemand}}
|
||||
OnHostRule = {{.OnHostRule}}
|
||||
caServer = "http://{{.BoulderHost}}:4000/directory"
|
||||
[acme.httpchallenge]
|
||||
entrypoint="http"
|
||||
|
||||
[file]
|
||||
|
||||
[backends]
|
||||
[backends.backend]
|
||||
[backends.backend.servers.server1]
|
||||
url = "http://127.0.0.1:9010"
|
||||
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend]
|
||||
backend = "backend"
|
||||
[frontends.frontend.routes.test]
|
||||
rule = "Host:traefik.acme.wtf"
|
||||
@@ -9,8 +9,8 @@
|
||||
[frontends.frontend.routes.test]
|
||||
rule = "Host:traefik.acme.wtf"
|
||||
|
||||
[[tlsConfiguration]]
|
||||
[[tls]]
|
||||
entryPoints = ["https"]
|
||||
[tlsConfiguration.certificate]
|
||||
[tls.certificate]
|
||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||
34
integration/fixtures/acme/wrong_acme.toml
Normal file
34
integration/fixtures/acme/wrong_acme.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
logLevel = "DEBUG"
|
||||
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
[api]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8081"
|
||||
[entryPoints.https]
|
||||
address = ":5001"
|
||||
[entryPoints.https.tls]
|
||||
|
||||
|
||||
[acme]
|
||||
email = "test@traefik.io"
|
||||
storage = "/dev/null"
|
||||
entryPoint = "https"
|
||||
OnHostRule = true
|
||||
caServer = "http://wrongurl:4000/directory"
|
||||
|
||||
[file]
|
||||
|
||||
[backends]
|
||||
[backends.backend]
|
||||
[backends.backend.servers.server1]
|
||||
url = "http://127.0.0.1:9010"
|
||||
|
||||
|
||||
[frontends]
|
||||
[frontends.frontend]
|
||||
backend = "backend"
|
||||
[frontends.frontend.routes.test]
|
||||
rule = "Host:traefik.acme.wtf"
|
||||
@@ -5,6 +5,8 @@ logLevel = "DEBUG"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
|
||||
|
||||
[consul]
|
||||
@@ -12,5 +14,5 @@ logLevel = "DEBUG"
|
||||
watch = true
|
||||
prefix = "traefik"
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
|
||||
@@ -3,6 +3,8 @@ defaultEntryPoints = ["http","https"]
|
||||
logLevel = "DEBUG"
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
[entryPoints.https]
|
||||
@@ -16,5 +18,5 @@ logLevel = "DEBUG"
|
||||
prefix = "traefik"
|
||||
watch = true
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
defaultEntryPoints = ["http"]
|
||||
logLevel = "DEBUG"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
|
||||
@@ -6,7 +6,7 @@ logLevel = "DEBUG"
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
|
||||
[web]
|
||||
[api]
|
||||
|
||||
[docker]
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ logLevel = "DEBUG"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8080"
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
|
||||
[dynamodb]
|
||||
AccessKeyID = "key"
|
||||
@@ -12,5 +14,5 @@ logLevel = "DEBUG"
|
||||
Endpoint = "{{.DynamoURL}}"
|
||||
Region = "us-east-1"
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
|
||||
@@ -5,6 +5,8 @@ logLevel = "DEBUG"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
|
||||
|
||||
[etcd]
|
||||
@@ -13,5 +15,5 @@ logLevel = "DEBUG"
|
||||
watch = true
|
||||
useAPIV3 = {{.UseAPIV3}}
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
@@ -3,6 +3,8 @@ defaultEntryPoints = ["http","https"]
|
||||
logLevel = "DEBUG"
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.api]
|
||||
address = ":8081"
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
[entryPoints.https]
|
||||
@@ -16,5 +18,6 @@ logLevel = "DEBUG"
|
||||
# prefix = "/traefik"
|
||||
# watch = true
|
||||
|
||||
[web]
|
||||
address = ":8081"
|
||||
|
||||
[api]
|
||||
entryPoint = "api"
|
||||
@@ -10,5 +10,4 @@ logLevel = "DEBUG"
|
||||
[eureka]
|
||||
endpoint = "http://{{.EurekaHost}}:8761/eureka"
|
||||
delay = "1s"
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
@@ -11,8 +11,7 @@ RootCAs = [ """{{ .CertContent }}""" ]
|
||||
keyFile = """{{ .KeyContent }}"""
|
||||
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ InsecureSkipVerify = true
|
||||
keyFile = """{{ .KeyContent }}"""
|
||||
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ logLevel = "DEBUG"
|
||||
[entryPoints.http2]
|
||||
address = ":9000"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
[backends]
|
||||
|
||||
@@ -8,8 +8,7 @@ logLevel = "DEBUG"
|
||||
[entryPoints.http2]
|
||||
address = ":9000"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
[backends]
|
||||
|
||||
@@ -6,8 +6,7 @@ logLevel = "DEBUG"
|
||||
[entryPoints.http]
|
||||
address = ":8000"
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
[api]
|
||||
|
||||
[file]
|
||||
[backends]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user