Compare commits
2919 Commits
v1.0.alpha
...
v2.0.0
Author | SHA1 | Date | |
---|---|---|---|
3d784a14f9 | |||
47a9b086ea | |||
e70c8a7b46 | |||
673351d821 | |||
4b966f1f82 | |||
93626de01c | |||
7847b7685d | |||
255e88fbf6 | |||
685c6dc00c | |||
8e18d37b3d | |||
b4c7b90c9e | |||
b55be9fdea | |||
401b3afa3b | |||
7fa3537015 | |||
149ed91afb | |||
887826ee68 | |||
7357d5eae2 | |||
e40e3af760 | |||
24a2788081 | |||
1388266102 | |||
43af0b051f | |||
6e8138e19b | |||
fb8edd86d5 | |||
34be181706 | |||
fcc1109e76 | |||
2b828765e3 | |||
25f4c23ab2 | |||
be90b20a5d | |||
232c113dae | |||
605a9b2817 | |||
d044c0f4cc | |||
1959e1fd44 | |||
6712423dd1 | |||
3689990bd5 | |||
81a1f618f9 | |||
b77bb690de | |||
f843f260ee | |||
770b3739e0 | |||
261e7c1744 | |||
10acbb8d92 | |||
a917115a85 | |||
b8ed6f1588 | |||
3ed57e01a6 | |||
cb7c5a8ca1 | |||
07eb9c5970 | |||
306e5081d9 | |||
259c7adc81 | |||
af9762cf32 | |||
17554202f6 | |||
0d9cf697fa | |||
df0dd2f5e6 | |||
38508f9a9c | |||
b113972bcf | |||
72e67bf4e9 | |||
da8aa2d8e4 | |||
602a2ea541 | |||
fd24b1898e | |||
89150e1164 | |||
e1831c4c60 | |||
4ec90c5c0d | |||
a8c73f7baf | |||
6fed76a687 | |||
84de444325 | |||
0fbd87ca87 | |||
99797502eb | |||
16bd0b9ca8 | |||
5fdfa963f4 | |||
1d86e71331 | |||
9e3f549341 | |||
2895ad21f3 | |||
5731ae7f47 | |||
51f7d9a07f | |||
6be390c795 | |||
0f32de4aa2 | |||
5d01452648 | |||
51b0508512 | |||
4c5e7a238d | |||
f327b7b499 | |||
306e86c9c6 | |||
9024f1b444 | |||
fc26e8c194 | |||
ffd8e5667c | |||
9299c3abc7 | |||
63a07fe6cf | |||
c2d440a914 | |||
2b5c7f9e91 | |||
91e63dea47 | |||
cd164de776 | |||
c0ef5ce512 | |||
7c852fbf33 | |||
28500989bc | |||
75c99a0491 | |||
8b4ba3cb67 | |||
3ef2971c3f | |||
a5aa8c6006 | |||
022d14abe1 | |||
1800b0b69c | |||
c39a550b00 | |||
092aa8fa6d | |||
f75f73f3d2 | |||
e3627e9cba | |||
d5f4934acf | |||
693bd7e110 | |||
4d8dcdc623 | |||
8e97af8dc3 | |||
4dc448056c | |||
68c349bbfa | |||
75aedc8e94 | |||
8b08f89d2c | |||
889b38f75a | |||
a17ac23457 | |||
6fdd48509e | |||
62800116d3 | |||
1bccbf061b | |||
093658836e | |||
f49800e56a | |||
e478dbeb85 | |||
51486b18fa | |||
48d98dcf45 | |||
2c7cfd1c68 | |||
7a4b4c941c | |||
608ccb0ca1 | |||
3f6ea04048 | |||
74c5ec70a9 | |||
c8bf8e896a | |||
09cc1161c9 | |||
8ab33db51a | |||
cc4258bf9d | |||
0ee5d3d83f | |||
c39aa5e857 | |||
39aae4167e | |||
9db9143366 | |||
49814b92fe | |||
260b5d6b0d | |||
4360ca14c1 | |||
c7d336f958 | |||
f6436663eb | |||
84d7c65039 | |||
4245096be4 | |||
c9b2a07bc7 | |||
e69d4cba88 | |||
96962dd21f | |||
36d48224b5 | |||
53779d6ceb | |||
e7e268b3bd | |||
ca2f76fe1f | |||
4d44ab9628 | |||
dd62051e6c | |||
fdb1701d1b | |||
80b35575df | |||
69cf05df9a | |||
69a1817c3f | |||
a918dcd5a4 | |||
adc9a65ae3 | |||
1e779f7135 | |||
fe68e9e243 | |||
e9792b446f | |||
4012599264 | |||
429b1d8574 | |||
a34876d700 | |||
68ecf78f0e | |||
38344b342d | |||
346ff96de2 | |||
31614bebc4 | |||
be888b59a6 | |||
6069df6cbd | |||
5e7b6e4860 | |||
ea6fa6e889 | |||
3e914256ce | |||
85ce16b34f | |||
d306c8fd50 | |||
8d7eccad5d | |||
d18edd6f77 | |||
cad3704efd | |||
9a4b455c3f | |||
01c8798e4e | |||
61744fba11 | |||
0034bef6b9 | |||
63c3ed3931 | |||
8a5db8a3ee | |||
adc2b62c22 | |||
1f2fe08c33 | |||
77b1933833 | |||
c4df78b4b9 | |||
c1dc783512 | |||
518a37e776 | |||
b143101f82 | |||
2be6f4d153 | |||
ac612734c8 | |||
ffe69c67fc | |||
b3057a0ec3 | |||
563f059e73 | |||
6bbe7262ef | |||
55a1a81010 | |||
97ec764db7 | |||
f6df556eb0 | |||
5cd9396dae | |||
886a6bdbe0 | |||
ab60e702d2 | |||
17141b3589 | |||
8f23243cb8 | |||
c2345c6e9a | |||
2617de2cdd | |||
9cf6827ccc | |||
681892148e | |||
558452a143 | |||
5a173fa968 | |||
72397ef90c | |||
79ad4b4544 | |||
49f3713c4f | |||
4b5c3ccf58 | |||
21dec70971 | |||
0f2b774ea1 | |||
e929caf15a | |||
8d848c3d60 | |||
b8b0c8f3e5 | |||
15e78da7eb | |||
d80700810f | |||
c1de6abf23 | |||
01b916eaa0 | |||
62c03b3318 | |||
65679af61d | |||
821ad31cf6 | |||
ea750ad813 | |||
3d7633f4a6 | |||
d356ef1c5b | |||
fce762febf | |||
535280c162 | |||
bb8a193244 | |||
e6bdfa1d29 | |||
d1d2611665 | |||
8389b46b5c | |||
b9f826554c | |||
0750235712 | |||
ee0e014617 | |||
2e20394af4 | |||
6ab991ebf4 | |||
ef8894ef26 | |||
8b4efa1760 | |||
b0b8b75258 | |||
2e19e45aa4 | |||
e1d097ea20 | |||
ed12366d52 | |||
4919b638f9 | |||
49563e638b | |||
07d0eb9ae6 | |||
336135c392 | |||
d2b38e6ac4 | |||
883f90dded | |||
58e82743f8 | |||
51a0994d2d | |||
da20db862d | |||
d6c9f51082 | |||
08d7bb0d08 | |||
1bcb3d8cc2 | |||
c17de070fb | |||
b893374dc1 | |||
fe532ed4f2 | |||
6377a19b12 | |||
ca7ea68a6a | |||
a45f285a5c | |||
fa2c57f7cb | |||
0779c6a139 | |||
2916f540c1 | |||
7932e317c8 | |||
fd26cf265d | |||
3e76c25887 | |||
a0e2f47679 | |||
d70add10ab | |||
119d0134e0 | |||
2e085fa253 | |||
f8f7edd124 | |||
79ecff7b42 | |||
0f2c4fb5f4 | |||
ec1952157b | |||
cd38359458 | |||
8a86777db8 | |||
e7033071b9 | |||
f99a473436 | |||
c4b7e8f288 | |||
f346251719 | |||
4c3cf87f62 | |||
cb417b8077 | |||
076d6abfe4 | |||
82308c9a53 | |||
5d35079809 | |||
50e24f461c | |||
37886892c8 | |||
72ffa91fe0 | |||
9908137638 | |||
f3ecc040c8 | |||
e271378a97 | |||
5d050ae3ac | |||
615ceab597 | |||
f1b085fa36 | |||
bd4c822670 | |||
03d5a95bde | |||
e2ec64947a | |||
dabd9e2208 | |||
4c060a78cc | |||
cfaf47c8a2 | |||
87da7520de | |||
4a68d29ce2 | |||
0ca2149408 | |||
0cfaab02c0 | |||
2d54065082 | |||
3cfbe7cf6d | |||
e2d8a95c91 | |||
3419f9aeb9 | |||
ebded2cbc0 | |||
fb617044e0 | |||
5a0b5470e7 | |||
6b4144ad10 | |||
8f16ff9c49 | |||
ac6b11037d | |||
848e45c22c | |||
2c0bf335ba | |||
aef24dd74b | |||
c2c6aee18a | |||
6451b47621 | |||
2b2cfdfb32 | |||
5f4d440493 | |||
5f0451affe | |||
156f6b8d3c | |||
f0ee2890b2 | |||
16c283c91a | |||
db13dbdf46 | |||
06905cb14a | |||
6ea9c4dd3f | |||
c5c8382742 | |||
115ddc6a4a | |||
54ca0ce34f | |||
f19c497621 | |||
0561a20c06 | |||
162490dadf | |||
30087794ba | |||
9ebe3c38b2 | |||
7155f0d50d | |||
75e05ca142 | |||
5d4423910d | |||
0de1ff8634 | |||
e5fb1ffeb7 | |||
8c53318dac | |||
0d6f259adc | |||
85ab0e6e70 | |||
a18294d417 | |||
fecd0ca391 | |||
97bd92c76f | |||
49b89c30d8 | |||
8228a8e3f7 | |||
78be3df99a | |||
2f0db9a974 | |||
227fab3867 | |||
9537449b07 | |||
246b245959 | |||
a433e469cc | |||
04958c6951 | |||
b54c956c5e | |||
8735263930 | |||
a79d6aa669 | |||
7efafa5a2c | |||
0b436563bd | |||
5d379dc3e3 | |||
8c60774c6a | |||
9b2423aaba | |||
fc8c24e987 | |||
d7bd69714d | |||
099bbb8be7 | |||
c29a69a60d | |||
69e4f35d9a | |||
ff40467207 | |||
190c6c661f | |||
e633799c14 | |||
f7c6c562a5 | |||
bc6e9d5042 | |||
a0b1d54012 | |||
60b5286f8c | |||
aa3ea17a8f | |||
698621f127 | |||
906f4fe8f7 | |||
ddf199566c | |||
a47d770e71 | |||
057498ed01 | |||
fa562dc916 | |||
0be895febb | |||
11a0078966 | |||
92f8e5cd3f | |||
5b3762be08 | |||
3b01488c8d | |||
2f65572247 | |||
e42ddfc3d6 | |||
d63636243c | |||
a0b9c0d007 | |||
1f7a4174ba | |||
761c58e040 | |||
01c3d3905c | |||
c815a732ef | |||
5d91c7e15c | |||
c39d21c178 | |||
b6498cdcbc | |||
a09dfa3ce1 | |||
d3ae88f108 | |||
1fad7e5a1c | |||
19546ab518 | |||
e6e9a86919 | |||
c6dd1dccc3 | |||
993caf5058 | |||
450471d30a | |||
7eeecd23ac | |||
21c94141ba | |||
bc2cba5aa4 | |||
5e49354bf2 | |||
55334b2062 | |||
74dc5b1c58 | |||
ac11323fdd | |||
8c2e99432d | |||
aa26927d61 | |||
22ee8700ca | |||
df55c24cb5 | |||
99ddd7f9cb | |||
82b2a102ed | |||
c7df82e695 | |||
638960284e | |||
8e9b8a0953 | |||
3f044c48fa | |||
37d8e32e0b | |||
46ce807624 | |||
e6a88f3531 | |||
95d86d84b4 | |||
70fa42aee0 | |||
ba99fbe390 | |||
6a55772cda | |||
6dcb51a4bd | |||
c875819a2e | |||
6d4cf0d892 | |||
78a9d20691 | |||
7c2409b5a7 | |||
0335f6fba9 | |||
2c7b7cd6ca | |||
5632952665 | |||
7eeac63139 | |||
1b54f4d32a | |||
e8e9dd9400 | |||
b722748ec3 | |||
609b2630d7 | |||
5bdf8a5ea3 | |||
7a2592b2fa | |||
546bebc860 | |||
ad51f4f2a5 | |||
94a6f8426b | |||
32f7fb8bff | |||
a777c3553c | |||
51650c1412 | |||
157580c232 | |||
05f052b092 | |||
1431ac5751 | |||
a9deeb321b | |||
ec86149b1e | |||
31f92001e2 | |||
d69977c229 | |||
44e06a1a1e | |||
f9689d1562 | |||
4cb1ae4626 | |||
f04813fa02 | |||
742029d8a4 | |||
f74526a36e | |||
61e1836472 | |||
8d8e509fe6 | |||
147e79ea07 | |||
5eae95ee46 | |||
9e26f0b058 | |||
8cc3c4a6b7 | |||
1d8bdd4384 | |||
5acd43efaf | |||
7033b996c6 | |||
0c76a8ac89 | |||
f10516deb7 | |||
d4311f9cf5 | |||
6a50a6fd5a | |||
29473ef356 | |||
1f1ecb15f6 | |||
38d655636d | |||
9ab5cbf235 | |||
fdf14cd101 | |||
f63873cc73 | |||
c2938ff138 | |||
ab2c98d931 | |||
0ae8cd9a9d | |||
f3aefe282c | |||
a80cca95a2 | |||
c52f4b043d | |||
253060b4f3 | |||
36966da701 | |||
bb7c4aaf7e | |||
bd4846aa9c | |||
c68ebaa2ca | |||
538424b01c | |||
48e7a87741 | |||
74ace58ae1 | |||
913d8737cc | |||
b98f5ed8b1 | |||
e4bb506ace | |||
0f0ba099c9 | |||
f400292be7 | |||
efc6560d83 | |||
4055654e9b | |||
56488d435f | |||
f586950528 | |||
a302731cd1 | |||
00728e711c | |||
ef753838e7 | |||
acb79d6f73 | |||
157c796294 | |||
0861c59bec | |||
e4a7375d34 | |||
6bbac65f7e | |||
845f1a7377 | |||
9c8e518423 | |||
bd3b787fd5 | |||
27e4a8a227 | |||
cf2d7497e4 | |||
df41cd925e | |||
e46de74328 | |||
feeb7f81a6 | |||
2beb5236d0 | |||
f062ee80c8 | |||
a7bb768e98 | |||
07be89d6e9 | |||
d81c4e6d1a | |||
870755e90d | |||
bd3c8c3cde | |||
278b3180c3 | |||
bb2686a08f | |||
202783ca7d | |||
308904110a | |||
60b4095c75 | |||
d04b4fa2cc | |||
2d449f63e0 | |||
1ec4e03738 | |||
9cd47dd2aa | |||
015cd7a3d0 | |||
7ff6e6b66f | |||
e92b01c528 | |||
bb33128552 | |||
86add29838 | |||
70712a0f62 | |||
4db937b571 | |||
ad6f41c77a | |||
e6040e55f5 | |||
dad0e75121 | |||
c159e316be | |||
b4ac3d4470 | |||
43d22d7a2f | |||
d62f7e2082 | |||
cfe2f1a1e6 | |||
6f6ebb8025 | |||
7732e2307e | |||
8c733abef3 | |||
4809476c19 | |||
d727761e5d | |||
4d79c2a6d2 | |||
8627256e74 | |||
ed0c7d9c49 | |||
fb4717d5f3 | |||
09b489a614 | |||
402f7011d4 | |||
838dd8c19f | |||
91cafd1752 | |||
eea60b6baa | |||
baf8d63cb4 | |||
967e4208da | |||
ba3a579d07 | |||
1d53077fc7 | |||
4b480ece13 | |||
7d2b7cd7f1 | |||
73b4df4e18 | |||
a23a9228da | |||
37aa902cef | |||
bafb583666 | |||
aabebb2185 | |||
f611ef0edd | |||
d8f69700e6 | |||
c8ae97fd38 | |||
d50b6a34bc | |||
853be929bc | |||
3bb04142f3 | |||
d53fbb9d7f | |||
a1911a9608 | |||
ff2e2d5026 | |||
a953d3ad89 | |||
9ce444b91a | |||
ae8be89767 | |||
5774d100c1 | |||
dbe720f0f1 | |||
5afc8f2b12 | |||
c7e008f57a | |||
14b7152bf0 | |||
3ef6bf2118 | |||
f0ab2721a5 | |||
2721c2017c | |||
a7c158f0e1 | |||
7ff9193cf5 | |||
5ce4a2d05c | |||
031451abab | |||
8d75aba7eb | |||
027093a5a5 | |||
bdc0e3bfcf | |||
b2a57ca1f3 | |||
6ef0e6791b | |||
9374d6b3b9 | |||
f173ff02e3 | |||
ba2046491a | |||
083b471bcf | |||
bf73127e0b | |||
333b785061 | |||
79bf19c897 | |||
0c0ecc1cdc | |||
bacd58ed7b | |||
689f120410 | |||
2303301d38 | |||
f323df466d | |||
b1f1a5b757 | |||
0d262561d1 | |||
12c713b187 | |||
b1836587f2 | |||
04d8b5d483 | |||
461ebf6d88 | |||
41eb4f1c70 | |||
31a8e3e39a | |||
139f280f35 | |||
17ad5153b8 | |||
bb14ec70bd | |||
e8e36bd9d5 | |||
f9b1106df2 | |||
df600d6f3c | |||
157e76e829 | |||
dbc3b85cd0 | |||
11691019a0 | |||
3192307d59 | |||
ba8c9295ac | |||
d5436fb28b | |||
886cc83ad9 | |||
9e012a6b54 | |||
5eda08e9b8 | |||
ec6e46e2cb | |||
56fe023a12 | |||
aa705dd691 | |||
aa6fea7f21 | |||
e31c85aace | |||
1c3e4124f8 | |||
586ba31120 | |||
c1757372d3 | |||
7451449dd6 | |||
5b2b29043c | |||
2758664226 | |||
bb3f28ffa7 | |||
6ceb2af4a7 | |||
d5b649bf1c | |||
81f23cc732 | |||
b59276ff1c | |||
2e95832812 | |||
01f2b3cd20 | |||
2240bf9430 | |||
db036edccd | |||
1fbf5b84a2 | |||
08e1f626c1 | |||
c0d08f5e3e | |||
eac20d61df | |||
dec3f0798a | |||
bddb4cc33c | |||
62ded580ce | |||
51227241b7 | |||
9cf4e730e7 | |||
e9c63f3988 | |||
2c47691cf1 | |||
599b699ac9 | |||
a5beeb4f04 | |||
446d73fcf5 | |||
e299775d67 | |||
2c18750537 | |||
f317e50136 | |||
1d84bda7ca | |||
ae7c947ba5 | |||
6d07729c55 | |||
1d7bf200a8 | |||
6bc59f8b33 | |||
b2cf03fa5c | |||
36e273714d | |||
6be77b7fb9 | |||
6bcf45f136 | |||
8bca8236db | |||
67a0b4b4b1 | |||
a7200a292b | |||
fb5aa4c9c1 | |||
3f5772c62a | |||
e76836b948 | |||
2d946d7ee7 | |||
10ca35dccd | |||
bfdd1997f6 | |||
9420308667 | |||
83e09acc9f | |||
d6d795e286 | |||
c09febfffc | |||
5b3bba8f6e | |||
085593b9e5 | |||
e2a5d4f83e | |||
e3671cbb04 | |||
a525d02cc5 | |||
3c8c5ebb96 | |||
1cc1a4e6e2 | |||
3f0af3fe09 | |||
e2bac47a0a | |||
bc26d9f0de | |||
5c4692a0df | |||
0ba28bbc8b | |||
550184275a | |||
c376083ecb | |||
1db5fcf200 | |||
16b2555ab3 | |||
9227d32d57 | |||
c37b040217 | |||
5a1d2aa4b6 | |||
4a3b1f3847 | |||
d9a5258f40 | |||
190ebbed27 | |||
a0872c9e31 | |||
68cc826519 | |||
f5b306e7ff | |||
7a1feb3c51 | |||
e691168cdc | |||
4eda1e1bd4 | |||
1e8df9f245 | |||
b72937e8fb | |||
df11e67bb4 | |||
b7d20496f3 | |||
67847c3117 | |||
a2a0c80acb | |||
b3fd06fb45 | |||
c5db8d903c | |||
8fcd242494 | |||
ebd9af900e | |||
b02381c2d5 | |||
dce65ab9c2 | |||
97295f270b | |||
8e64bc8785 | |||
9b199ea756 | |||
ec3b913ee4 | |||
c210ab31d9 | |||
6c1fa91c70 | |||
04bab185f6 | |||
2213b4cf37 | |||
1d770e5636 | |||
b7e15e0a2c | |||
9c651ae913 | |||
a1bbaec71f | |||
3b3ca89483 | |||
b4e3bca6fa | |||
e09d5cb4ec | |||
cae353b9f6 | |||
edb5b3d711 | |||
667a0c41ed | |||
9daae9c705 | |||
2975acdc82 | |||
76dcbe3429 | |||
d8e2d464ad | |||
5f8bcb0c26 | |||
7ef8d6fa10 | |||
5924a40222 | |||
05968eb232 | |||
36dcfbfe2d | |||
95ce4f5c1e | |||
f258f20b04 | |||
7e2ad827aa | |||
e6ce61fdf0 | |||
3df588047d | |||
ac0e5cbb29 | |||
5ab584bc6a | |||
a2e03e3bd0 | |||
f0589b310f | |||
8519b0d353 | |||
21b8b2deb5 | |||
6b82a77e36 | |||
1954a49f37 | |||
0e3d1e1503 | |||
ebd77f314d | |||
749d833f65 | |||
0373cd6f97 | |||
1f3fc8a366 | |||
89c3930b28 | |||
29e1e9eef2 | |||
de3aeb9732 | |||
85aa1a444a | |||
702876ae7f | |||
7109910f46 | |||
8168d2fdc1 | |||
edbcd01fbc | |||
c99266e961 | |||
f804053736 | |||
2641832304 | |||
21f6f81914 | |||
ccd919aba3 | |||
2387010556 | |||
f35d574759 | |||
3be74bb275 | |||
b1be062437 | |||
2d0d320d05 | |||
1de5111ab5 | |||
3d530e4747 | |||
0ef1b7b683 | |||
66485e81b4 | |||
e74e7cf734 | |||
03ce6a1cc4 | |||
a19b93c966 | |||
f7fd1f2a63 | |||
88b71d23db | |||
762ef12eb6 | |||
6845068b82 | |||
5c0b18efe4 | |||
4b93d040b3 | |||
ff61cc971e | |||
46db91ce73 | |||
5921909ef5 | |||
1537861c61 | |||
1b93551572 | |||
197a5fbcf4 | |||
ff32529345 | |||
a179c3b399 | |||
a820585f56 | |||
bfb12f415c | |||
a731b43b52 | |||
118b4eb07a | |||
f1a05ab73c | |||
4c85a41bfb | |||
30e048d4ab | |||
aa0ab6d387 | |||
30b87985b7 | |||
df73211d56 | |||
e3a4ddcd08 | |||
0ea007b26f | |||
16bb9b6836 | |||
d2766b1b4f | |||
4802484729 | |||
c762b9bb2e | |||
5792a19b97 | |||
9699dc2a85 | |||
0fa0c2256a | |||
1b410980ca | |||
be0dbd62c1 | |||
1a411b658b | |||
d2e84a700f | |||
b9af55fc49 | |||
e0d92aed6d | |||
f94fa78565 | |||
007a1fc7f2 | |||
a3372acb6d | |||
af7c9b520f | |||
43a510c046 | |||
329c576f44 | |||
7afa33dfa1 | |||
73c6007730 | |||
526c19181e | |||
79cd306ac2 | |||
35b83678bd | |||
eacb6ea15a | |||
d88263dbf9 | |||
b1e3444798 | |||
f6c6d2bcd0 | |||
8d468925d3 | |||
f99363674b | |||
526a04d4c8 | |||
593c0e7ce2 | |||
e2b42ca57b | |||
7860534f0c | |||
fc81d92c88 | |||
8fbac2e39e | |||
b91ae71241 | |||
0a41cd43a5 | |||
59f7b2ea98 | |||
862957c30c | |||
4831890232 | |||
546f0173ab | |||
b001b0da86 | |||
04e3f2f401 | |||
3a2b421566 | |||
acc432b5a8 | |||
c4529820f2 | |||
d3edccb839 | |||
8380de1bd9 | |||
bf43149d7e | |||
13e2358815 | |||
1f6f8d5e0f | |||
716eca5976 | |||
9ae808aac4 | |||
c77fe6b434 | |||
f149b56063 | |||
831a3e384b | |||
49a9e2a9e0 | |||
a2db3e0499 | |||
422109b82f | |||
c864a7297b | |||
8da038041d | |||
dd954f3c0a | |||
6f81e3479a | |||
db483e9d34 | |||
700b7a1b51 | |||
ed65d00574 | |||
0306b5e8f7 | |||
cb54e414ed | |||
bad71d1a36 | |||
088b8fb348 | |||
e28ebf1c62 | |||
39eeb67d91 | |||
f460c1990e | |||
0c0949679f | |||
58d4481118 | |||
83381e99cf | |||
21e28ae848 | |||
31550fd2c9 | |||
7c7ee2ca61 | |||
ba046b4d3a | |||
d675d46930 | |||
7ea76929d4 | |||
5ef55dd8b4 | |||
d47c1a7975 | |||
8068057040 | |||
fcdeec0bfa | |||
b9d8eff994 | |||
529e34d2ae | |||
26b3fe201b | |||
f98c537ec2 | |||
083bde64ee | |||
462dcbcf03 | |||
45fe218ee2 | |||
d54777236c | |||
dafdaa4208 | |||
5212b7d3bd | |||
83a92596c3 | |||
4f3b06472b | |||
029fa83690 | |||
abdcb9e332 | |||
17e85e31cd | |||
7d3dd5a0e4 | |||
dd873fbeee | |||
38a4c80995 | |||
91fa727c74 | |||
794c0206f3 | |||
52bad03c8d | |||
2fde3e8679 | |||
1e71f52b72 | |||
2b1d2853cd | |||
6a92ac0b7b | |||
f07e8f58e6 | |||
7b19cb5631 | |||
f5adea1061 | |||
dbd173b4e4 | |||
85cfd87c44 | |||
c867f48f11 | |||
514f9a7215 | |||
0b0380b690 | |||
4d0c8c189a | |||
afe4c307f9 | |||
c0563f1a39 | |||
ce3a0fdd46 | |||
ce3c72e9d9 | |||
dcba74deb9 | |||
203a5c5c48 | |||
be4aeaacde | |||
04ebd9d46a | |||
52b4e93c38 | |||
58d6681824 | |||
c944d203fb | |||
62df067fac | |||
7c80b9a692 | |||
a4a8345a33 | |||
742dde72bb | |||
4497ddbb0e | |||
53388a3570 | |||
1c495d7ea4 | |||
4c0d6e211b | |||
5bfd6acd52 | |||
0b49de94c6 | |||
7c0e557f84 | |||
a81171d5f1 | |||
26dc2f4d61 | |||
d426126a92 | |||
6aac78fc36 | |||
f6c53f0450 | |||
54e09b98c7 | |||
395b1702de | |||
4eebaa1a80 | |||
cb9bf3ce68 | |||
ef4aa202d0 | |||
cc5ee00b89 | |||
49a8cb76f5 | |||
bf12306f17 | |||
fa1f4f761d | |||
b50aebd2ed | |||
323b8237a0 | |||
9f741abd84 | |||
32ccc26712 | |||
563a0bd274 | |||
a91080b060 | |||
039ccaf4f1 | |||
c878d262bf | |||
c8446c2dc8 | |||
4afb39778a | |||
751781a3b7 | |||
f5d150c3b4 | |||
ae9342208e | |||
3040d9df0d | |||
00e0571811 | |||
bfb07746fe | |||
171cda6186 | |||
4cc17e112f | |||
b6af61fa6e | |||
4e07d92190 | |||
fb4ba7af2b | |||
c134dcd6fe | |||
fc00e1c228 | |||
ae34486b57 | |||
d7b513e9aa | |||
d8297a055a | |||
5140bbe99a | |||
0c33d110f4 | |||
5b37fb83fd | |||
bc6879ecc1 | |||
17137ba3e7 | |||
e9d2124885 | |||
f1f2e1bf64 | |||
ced5aa5dc6 | |||
72bc74001f | |||
adfa3f795c | |||
89d90de7d8 | |||
fe426f6fb2 | |||
3e439cc39b | |||
56c0634918 | |||
bcadd68904 | |||
9790aa91fe | |||
5316b412d2 | |||
b5ee5c34f2 | |||
2618aef008 | |||
8239e04a19 | |||
709d50836b | |||
e2c5f3712f | |||
ee71b4bfef | |||
0d57e2aed9 | |||
30ffba78e6 | |||
8394549857 | |||
d0f3ad6024 | |||
870c0b5cf4 | |||
044d87d96d | |||
b60edd9ee9 | |||
b1ea36793b | |||
750878d668 | |||
617b8b20f0 | |||
d88554fa92 | |||
e74a20de24 | |||
7c227392fa | |||
8a697f7a39 | |||
8327dd0c0b | |||
60fd26e0b7 | |||
acd0c1bcd5 | |||
9b3750320b | |||
b9f1f7752d | |||
944008661f | |||
79ae52aca7 | |||
51390aa874 | |||
cfa1f47226 | |||
40b59da224 | |||
f7ed4a5805 | |||
3d47030349 | |||
34eb2e371e | |||
6573634012 | |||
61ecb4cd18 | |||
22bdbd2498 | |||
287fb78654 | |||
06d528a2bd | |||
1fe6a8b04d | |||
bd5cab6e87 | |||
238acd9330 | |||
8e7ac513b6 | |||
e56551d047 | |||
170fc13e02 | |||
97ce77169a | |||
c9b871a03a | |||
2fdefa258e | |||
f0a733d6d6 | |||
586b5714a7 | |||
6e23454202 | |||
5b24403c8e | |||
e83599dd08 | |||
de7dd068d9 | |||
a33476dea8 | |||
dceccbdb92 | |||
393651f5e2 | |||
5acee9e11d | |||
81626eef38 | |||
e60fbbbebe | |||
e45e63dc37 | |||
c3d5ad2eeb | |||
7c64f5d31e | |||
66f46c5b96 | |||
07a6d48a27 | |||
722ea28e3a | |||
f195ef27f3 | |||
7e5c258266 | |||
38b5aef208 | |||
a7e4ded722 | |||
22405a1259 | |||
d0a6689413 | |||
a1f47cb4db | |||
c884c7bb8a | |||
c042098889 | |||
571f41dcf0 | |||
f30ad20c9b | |||
cbd54470ba | |||
01e17b6c3e | |||
3e13ebec93 | |||
c84fb9895e | |||
23c1a9ca8e | |||
741c739ef1 | |||
52f16e11a8 | |||
5623a53464 | |||
c95393b238 | |||
be0dd71bb4 | |||
0ee6973e2f | |||
4819974a1c | |||
e8e8b41eed | |||
7d23d3c0a4 | |||
718fc7a79d | |||
bfd142b13b | |||
75533b2beb | |||
e3d1201b46 | |||
8f982ff1f2 | |||
0391e21c84 | |||
b8a1cb5c68 | |||
7a71cd3012 | |||
26bedced35 | |||
c1aefb8ad8 | |||
576e87f398 | |||
b4f6bf0f6a | |||
edc55aad3c | |||
38a3fe4316 | |||
81e3b2dd4c | |||
4524cdc151 | |||
9a7821b8fa | |||
e8333883df | |||
aeffe1036d | |||
987e8a93bd | |||
2cb4acd6cc | |||
1e44e339ad | |||
59549d5f39 | |||
4a7297d05c | |||
a5335667bb | |||
498b806ca9 | |||
dd7a8a9a87 | |||
133aa77c21 | |||
942614dd23 | |||
c30ebe5f90 | |||
50757b5e99 | |||
42b900b9b2 | |||
c26b9b1a5d | |||
9ee642a7db | |||
423385bca0 | |||
6e5f7650a5 | |||
89a79d0f1b | |||
9e41485ff1 | |||
3c7c6c4d9f | |||
cd1b3904da | |||
b23b2611b3 | |||
877770f7cf | |||
3142a4f4b3 | |||
b4dc96527d | |||
35b5ca4c63 | |||
daf3023b02 | |||
705f3f1372 | |||
f6520727a3 | |||
b17d5b80b8 | |||
48b4eb5c0d | |||
7ecd6d20ba | |||
bddad57a7b | |||
799136a714 | |||
350d61b4a6 | |||
b6f5a66fab | |||
b0c12e2422 | |||
623a7dc7e6 | |||
709c7e5707 | |||
5f6c5025d5 | |||
328be161d6 | |||
ee04f52a16 | |||
c446c291d9 | |||
c66d9de759 | |||
260ee980e0 | |||
7d98c1c4e0 | |||
4387cf38d7 | |||
a9d38570ab | |||
0e619369fd | |||
6890dc1844 | |||
cda09c843a | |||
e2190bd9d5 | |||
0472d19bd4 | |||
07524f5c99 | |||
1710800cc0 | |||
c705d6f9b3 | |||
be718aea11 | |||
ca680710a2 | |||
5f71a43758 | |||
04dd63da1c | |||
cee022b935 | |||
ae2ae85070 | |||
ce6bbbaa33 | |||
6333bfe6e8 | |||
41d8863d2f | |||
523b7f96f8 | |||
ab1a930705 | |||
dc74f76a03 | |||
3a99c86cb3 | |||
d6ad7e2e64 | |||
aaf120f263 | |||
c228e73b26 | |||
e27e65eb76 | |||
1c8acf3929 | |||
40b3c17703 | |||
e042ef3f27 | |||
313357a6b3 | |||
37a1aaad64 | |||
f084d2a28b | |||
077b39d7c6 | |||
7081f3df58 | |||
9fe6a0a894 | |||
3d452fd5b9 | |||
47a5cfbd3e | |||
4cb6241e93 | |||
b572879691 | |||
ad07a6ab2b | |||
4bdeb33ac1 | |||
101a4d0d8d | |||
89e07d0c55 | |||
39c1cc1b3c | |||
9f6f637527 | |||
0f09551a76 | |||
8cd72cfc1b | |||
7a141c8616 | |||
0ca65f955d | |||
011b748a55 | |||
f6181ef3e2 | |||
24368747ab | |||
66591cf216 | |||
1feeeb2eec | |||
419d46c958 | |||
7063da1c7d | |||
bee8ebb00b | |||
da5e4a13bf | |||
5dc1ec68a3 | |||
3d2e5ebe39 | |||
f5130db6b0 | |||
676b79db42 | |||
6d2f4a0813 | |||
4b91204686 | |||
7ddefcef72 | |||
0f3e42d463 | |||
c9129b8ecf | |||
a6955ecf59 | |||
6619a787a3 | |||
aae17c817b | |||
ab87bad952 | |||
be306d651e | |||
8fe5c22075 | |||
05a9350e57 | |||
7ed4ae2f8c | |||
5d6384e101 | |||
1a4564d998 | |||
66e489addb | |||
cdab6b1796 | |||
722f299306 | |||
66be04f39e | |||
8719f2836e | |||
0c702b0b6b | |||
6fcab72ec7 | |||
77b111702b | |||
96a7cc483f | |||
1e3506848a | |||
5ee2cae85c | |||
5c119fe2d6 | |||
d55115844a | |||
4f4491c247 | |||
1691f586d7 | |||
04dfe0de84 | |||
27d1b46835 | |||
2f62ec3632 | |||
384488ac02 | |||
c469e669fd | |||
56affb90ae | |||
f6aa147c78 | |||
9bd0fff319 | |||
00d7c5972f | |||
58a438167b | |||
e3131481e9 | |||
bc8d68bd31 | |||
07c6e33598 | |||
70812c70fc | |||
d89b234cad | |||
2070aa9443 | |||
91ff94ea56 | |||
0347537f43 | |||
db9b18f121 | |||
ee70001be3 | |||
972eea97fe | |||
2b4d33e919 | |||
fc4d670c88 | |||
02035d4942 | |||
93a46089ce | |||
e8d63b2a3b | |||
d3c7681bc5 | |||
dc66db4abe | |||
a0e1cf8376 | |||
5292b84f4f | |||
b27455a36f | |||
5042c5bf40 | |||
da7b6f0baf | |||
9b5845f1cb | |||
e8633d17e8 | |||
d1d8b01dfb | |||
7c4353a0ac | |||
1b2cb53d4f | |||
3158e51c62 | |||
a0c72cdf00 | |||
f0371da838 | |||
44b82e6231 | |||
04f0bf3070 | |||
7400c39511 | |||
008a5af6d6 | |||
35ca40c3de | |||
de821fc305 | |||
e3cac7d0e5 | |||
81f7aa9df2 | |||
6bce298d90 | |||
afbad56012 | |||
d973096464 | |||
7192aa86b5 | |||
9c8df8b9ce | |||
ff4c7b82bc | |||
47ff51e640 | |||
08503655d9 | |||
3afd6024b5 | |||
aa308b7a3a | |||
9598f646f5 | |||
8af39bdaf7 | |||
914f3d1fa3 | |||
8cb3f0835a | |||
cba0898e4f | |||
8d158402f3 | |||
7f2582e3b6 | |||
dbc796359f | |||
4d1285d8e5 | |||
871d097b30 | |||
1532033a7f | |||
9faae7387e | |||
a5c644e719 | |||
7a2ce59563 | |||
14cec7e610 | |||
6287a3dd53 | |||
93a1db77c5 | |||
a9d4b09bdb | |||
ed2eb7b5a6 | |||
18d8537d29 | |||
72f3b1ed39 | |||
fd70e6edb1 | |||
5a578c5375 | |||
9db8773055 | |||
8a67434380 | |||
c94e5f3589 | |||
adef7200f6 | |||
cf508b6d48 | |||
f8d36fda28 | |||
4fe9cc7730 | |||
758b7f875b | |||
0b97a67cfa | |||
ec5976bbc9 | |||
5cc49e2931 | |||
b6752a2c02 | |||
d41e28fc36 | |||
64c52a6921 | |||
691a678b19 | |||
1ba7fd91ff | |||
1c98a9ad3e | |||
dd23ceeead | |||
058fa1367b | |||
9db12374ea | |||
fc550ac1fc | |||
d6ef8ec3d1 | |||
837db9a2d9 | |||
a941739f8a | |||
795a346006 | |||
9d00da7285 | |||
52c1909f24 | |||
2cbf9cae71 | |||
f9225c54ff | |||
cb05f36976 | |||
49e0e20ce2 | |||
7c35337999 | |||
2296aab5a8 | |||
ce3b255f1a | |||
3942f3366d | |||
df76cc33a5 | |||
cf387d5a6d | |||
0a0cf87625 | |||
1a2544610d | |||
5229b7cfba | |||
243b45881d | |||
883028d981 | |||
bdeb7bfb9f | |||
808ffb0491 | |||
5305a16350 | |||
63b581935d | |||
c7c9349b00 | |||
d54417acfe | |||
9fba37b409 | |||
6d28c52f59 | |||
f80a6ef2a6 | |||
ecf31097ea | |||
16fc3675db | |||
651d993d9c | |||
03eb5139a2 | |||
286d882f1e | |||
3b6afdf80c | |||
c19cce69fa | |||
5c4931e235 | |||
b705e64a8a | |||
7fd1eb3780 | |||
8c5514612f | |||
924e82ab0c | |||
adcb99d330 | |||
8339139400 | |||
a43cf8d2b8 | |||
2b863d9bc2 | |||
9ce4f94818 | |||
5157a6ad47 | |||
cd6c58a372 | |||
03ba8396f3 | |||
b0a0e16136 | |||
732d73dd43 | |||
e075dfe911 | |||
425b53585a | |||
d5bbb103d4 | |||
5c2849ea07 | |||
723418e2cc | |||
45e2e8baec | |||
b0ae6bc049 | |||
ffb53c07b8 | |||
f329b3b51d | |||
5b27aba3e1 | |||
7c2ba62b56 | |||
24862402e5 | |||
d568d2f55a | |||
dae7e7a80a | |||
23cdb37165 | |||
2c82dfd444 | |||
c8c31aea62 | |||
89b0037ec1 | |||
b75fb23887 | |||
52b69fbcb8 | |||
f16219f90a | |||
7b0cef0fac | |||
e0af17a17a | |||
92fb86b66f | |||
919295cffc | |||
086a85d2f0 | |||
8235cd3645 | |||
f1a257abf8 | |||
98dfd2ba0e | |||
87e6285cf6 | |||
0d56a98836 | |||
8105f1c379 | |||
e6c2040ea8 | |||
c1b5b740ff | |||
1d2d0cefaa | |||
04e65958ee | |||
8765494cbd | |||
05665f4eec | |||
78544f7fa2 | |||
396449c07f | |||
eda679776e | |||
69d57d602f | |||
32b2736efd | |||
3f650bbd11 | |||
5313922bb7 | |||
ec3e2c08b8 | |||
40e18db838 | |||
0367034f93 | |||
b80ecd51a7 | |||
14a0d66410 | |||
d84ccbc52a | |||
1190768f4b | |||
ea3510d1f3 | |||
3f76f73e8c | |||
759c269dee | |||
c360395afc | |||
60a35c8aba | |||
50dd2b8cff | |||
4e5fcac9cb | |||
64b8fc52c3 | |||
19a5ba3264 | |||
7ff6c32452 | |||
ff11467022 | |||
7d3878214a | |||
984817d3a0 | |||
6b133e24b9 | |||
990ee89650 | |||
8071f31721 | |||
d456c2ce6a | |||
413ed62933 | |||
1b4dc3783c | |||
94f922cd28 | |||
29390a3c4a | |||
1db9482a8e | |||
888e6dcbc8 | |||
765c44d77f | |||
64ee68763b | |||
4122aef12e | |||
8cb44598c0 | |||
69c628b626 | |||
cd28e7b24f | |||
40d9058bb6 | |||
c36e0b3b06 | |||
3174fb8861 | |||
074b31b5e9 | |||
16609cd485 | |||
a09a8b1235 | |||
70ab34cfb8 | |||
36ee69609e | |||
c53be185f4 | |||
779eeba650 | |||
58ffea6627 | |||
a2d68ed881 | |||
d653a348b1 | |||
2e84b1e556 | |||
bbb133d94c | |||
d90fa5ab3e | |||
759a19bc4f | |||
a7ec785994 | |||
46faa7a745 | |||
54e3f08833 | |||
b365836c57 | |||
242f1b9c3c | |||
4dfbb6d489 | |||
c31b4c55c2 | |||
ca5bbab20a | |||
41dd124a4b | |||
dbf6161fa1 | |||
7aabd6e385 | |||
cb203f8e7e | |||
8f845bac74 | |||
98b52d1f54 | |||
4892b2b0da | |||
a89eb122a0 | |||
b7daa2f3a4 | |||
91ce78da46 | |||
7d178f49b4 | |||
85f4f26942 | |||
eee8ba8a53 | |||
22aceec426 | |||
121c057b90 | |||
2c976227dd | |||
81d011e57d | |||
3776e58041 | |||
f06e256934 | |||
4699d6be18 | |||
6473002021 | |||
4d89ff7e18 | |||
c5c63071ca | |||
9fbe21c534 | |||
36c88111de | |||
7a34303593 | |||
2201dcd505 | |||
7a7cafcbaa | |||
efb671401d | |||
4128c1ac8d | |||
73e10c96cc | |||
fdb24c64e4 | |||
631079a12f | |||
0055965295 | |||
f99f3b987e | |||
34e60a8404 | |||
ceec81011b | |||
927003329e | |||
01bb0a80ab | |||
db1baf80a9 | |||
9cb07d026f | |||
984ea1040f | |||
447109e868 | |||
f79317a435 | |||
131d8dd765 | |||
b452695c20 | |||
f17785c3ab | |||
fe4d0e95b3 | |||
0fb63f4488 | |||
2a578748fd | |||
d87c4d89e9 | |||
ccc429e36c | |||
0d25ba3cbc | |||
2ddae2e856 | |||
885b9f371c | |||
f275e4ad3c | |||
aea7bc0c07 | |||
a457392ec3 | |||
37ec7d0505 | |||
8f6404ab3a | |||
1538b16b21 | |||
a6477fbd95 | |||
e802dcd189 | |||
931dc02c09 | |||
7017cdcf49 | |||
5aa017d9b5 | |||
a7297b49a4 | |||
3eaeb81831 | |||
7d6c778211 | |||
9c27a98821 | |||
ad54c5a278 | |||
96939e2990 | |||
5268db47a1 | |||
3048509807 | |||
7399a83c74 | |||
18c3d8dc62 | |||
2d1ddcf28b | |||
a1a0420314 | |||
2223587fc0 | |||
63f9bccf9f | |||
18d11e02d0 | |||
a71d69cc3c | |||
e007bb7546 | |||
7874ffd506 | |||
a9216e24f5 | |||
39388a2199 | |||
71111708d4 | |||
ac5ab13a4c | |||
d5efc99876 | |||
1e84e77a67 | |||
1db22a6e63 | |||
d6b448f430 | |||
e1e07f7750 | |||
e426b27581 | |||
b6c5c14447 | |||
cbccdd51c5 | |||
4c4eba4b56 | |||
994e135368 | |||
87e5cda506 | |||
2833d68f15 | |||
dbfd2663c2 | |||
64e8b31d49 | |||
5b896bb46c | |||
bc0121808a | |||
4293446111 | |||
9967494996 | |||
b392023c37 | |||
f7d9dfafd0 | |||
2643271053 | |||
219a6372b0 | |||
5b36b274a3 | |||
8ad31d6eb4 | |||
2e762e76f3 | |||
13e8a875cf | |||
c7281df230 | |||
987ae92f53 | |||
5f0b215e90 | |||
55f610422a | |||
a04ef15bcd | |||
81754840ff | |||
2610023131 | |||
c1220b8765 | |||
bc6f764a87 | |||
0b414ed482 | |||
ff3481f06b | |||
f8ea19d29c | |||
3b8ebf7d33 | |||
5e14f20786 | |||
96b19deac5 | |||
a6aff7c85c | |||
1310347395 | |||
40c94d80d7 | |||
f521e72f15 | |||
88ea0a037b | |||
c963cee3c8 | |||
0be353d435 | |||
6afff2d403 | |||
12fa144f2f | |||
ac0e48b48c | |||
64aa37858b | |||
5348d4dccd | |||
c3c599241f | |||
c19432f95c | |||
bdf4f48d78 | |||
21aa0ea2da | |||
921a704c24 | |||
3f490f95c6 | |||
24d80b1909 | |||
f8e7b5595b | |||
f9839f7b1d | |||
2c45428c8a | |||
30aa5a82b3 | |||
3f68e382fd | |||
9e57a283d7 | |||
eaedc1b924 | |||
e3ab4e4d63 | |||
48a91d05b5 | |||
111251da05 | |||
71cec1580b | |||
78b2fba033 | |||
218b76275c | |||
cf5b6d837f | |||
0babc7bb64 | |||
8a551d91fd | |||
eeed035ef0 | |||
33404a7772 | |||
bd90745528 | |||
ede1212cb0 | |||
2dcbc01e51 | |||
61ba50fac9 | |||
b24b5e20b4 | |||
ffe1104851 | |||
3112432480 | |||
aa4ed088bb | |||
3a4ec19817 | |||
d2b204a075 | |||
94f5b0d9ff | |||
d2c8824902 | |||
fe6c35bc6b | |||
db09007dbc | |||
5b2e8990f1 | |||
2f6068decc | |||
1e591dd188 | |||
6838a81e50 | |||
ceef5e39b7 | |||
ef339af623 | |||
acc7865542 | |||
c00c240c14 | |||
3fd6da06e0 | |||
95502aeec3 | |||
58c786ca8c | |||
b6916d2f8c | |||
840c131a98 | |||
219bcec40f | |||
ccda550ab1 | |||
b5e73cfa07 | |||
ba928dd459 | |||
6fd40dbaa9 | |||
6ad273b9fa | |||
5500658f5a | |||
b4f9e3890f | |||
df6741aeeb | |||
5535318cda | |||
4e186cecf9 | |||
8ac281f9e3 | |||
e7a73d3fb3 | |||
ca9e36ebe3 | |||
138fea17ed | |||
bf3f6e2029 | |||
ec245d604a | |||
69e081f40f | |||
82651985c4 | |||
a5384bae47 | |||
1dcf8d2ea6 | |||
e86df016c3 | |||
72baf746f4 | |||
91b4b47f04 | |||
79cbe56a41 | |||
f621d7a2c4 | |||
3c33eab35e | |||
b67a27d0c7 | |||
8de107866f | |||
b5283391dd | |||
420a6db3b4 | |||
89da3b15a4 | |||
dcc4d92983 | |||
12c2d398a7 | |||
4e238280bc | |||
bd6056c269 | |||
acb0492e26 | |||
a0d6594e99 | |||
65f81990a7 | |||
1b85dd0455 | |||
bec45bc7d6 | |||
4c4b05d024 | |||
228ad9a244 | |||
2f06f339ec | |||
eefcf026d2 | |||
ccb1a4ff8c | |||
78f1b4216e | |||
44db6e9290 | |||
e2fdc27d64 | |||
25345427c3 | |||
ce492895e2 | |||
5d43b9e16a | |||
71a2c8bdcd | |||
8fd6160758 | |||
d57f83c31c | |||
441d5442a1 | |||
bf3673879f | |||
74925ba996 | |||
de6d771bc2 | |||
2f1a7cbf26 | |||
d24ba90900 | |||
9ed55e9eae | |||
a0c3d6a421 | |||
521e295349 | |||
aa8375e82b | |||
5a8215a1e4 | |||
7eb3051a57 | |||
a4355569af | |||
16c86022bb | |||
e615e833bc | |||
592a12dca2 | |||
97a3564945 | |||
f1ee471b6b | |||
750fa22cff | |||
099d605aed | |||
f1bc80ca12 | |||
49a9aeb95f | |||
25abf8b8f8 | |||
962fb908c0 | |||
b44aca64e3 | |||
34b21b9374 | |||
972579e2a0 | |||
ccff8a80f5 | |||
4f2a2d573d | |||
af1d0a7dce | |||
37e40bc776 | |||
d9fd412e0e | |||
4bc2f17b08 | |||
d1b65adfb1 | |||
19a7d22eef | |||
6012a0f3c5 | |||
4e81d41d06 | |||
f4579e5f12 | |||
a8cbe7ef5e | |||
6ba17847ab | |||
378a34c454 | |||
f38d117a31 | |||
73a1b172ed | |||
4310bdf3ca | |||
6cb8df9d1e | |||
93e123b489 | |||
8764c43eaf | |||
10e22c0b3f | |||
051f0c6855 | |||
809103f4b2 | |||
b7c2e2d3f1 | |||
d866a62b56 | |||
22ac60205a | |||
de557d031b | |||
7fcb7b86d3 | |||
9c9015a7b1 | |||
360e8e19ce | |||
dd52ee9f9b | |||
8a892b21e1 | |||
4e0f131fcd | |||
d1ee72b308 | |||
f03a9e502f | |||
542c3673e4 | |||
2d00758b2e | |||
73f09f389e | |||
29bada9ae3 | |||
4ce2c8cc34 | |||
b02b11a606 | |||
e38fa25412 | |||
38b2362a31 | |||
13754f06e3 | |||
ade223cf2e | |||
2118f6992a | |||
b04ba36682 | |||
3f293ee25b | |||
dc01094863 | |||
fa683fa7e4 | |||
1da47dfcbb | |||
fc3cc9a919 | |||
12a0026e21 | |||
aeb17182b4 | |||
a590155b0b | |||
87ce060737 | |||
f2297dd3ed | |||
2cd4c82092 | |||
6edc0926eb | |||
a456d36cc6 | |||
5c2d91ab84 | |||
a73fee50dc | |||
b02393915e | |||
b99a919bb4 | |||
51f3f6ba9c | |||
736f9b30ef | |||
b385ffaee7 | |||
b02e289734 | |||
fd1cf2484c | |||
5250c9c04d | |||
e011792a90 | |||
a507cb4835 | |||
f324983946 | |||
c876462eb0 | |||
ec7ba15955 | |||
ef83a5936d | |||
8d650da2f8 | |||
bd127168b3 | |||
1ecdadb283 | |||
d8c21639f7 | |||
d2df47d382 | |||
0cc3d05515 | |||
60ea9199e5 | |||
637c7e250c | |||
6f4c5dd4ce | |||
a3b95f798b | |||
65284441fa | |||
51e4dcbb1f | |||
e38bf0accb | |||
08c1871c98 | |||
4eb779e596 | |||
e1aa16ae70 | |||
b4dfb7223b | |||
f621a46a2e | |||
c864d80270 | |||
020a8e31ab | |||
69c31276f2 | |||
06c47134c9 | |||
c9d23494b9 | |||
7d256c9bb9 | |||
056fe9ac0a | |||
e375ba98f0 | |||
d6d93db13b | |||
3389908238 | |||
5c16860486 | |||
0a7f9b5a71 | |||
df685fa050 | |||
2c079b3d6f | |||
35973f1243 | |||
9281f4fbbc | |||
0e0a231e5a | |||
b22716c5ba | |||
240b2be1a8 | |||
c5125cee71 | |||
1cf1fbf99b | |||
1ed68b1278 | |||
84e1ec6607 | |||
1140ee6c64 | |||
8401cccff2 | |||
836f617286 | |||
1bc8c9912e | |||
b5430803b8 | |||
a7bc8c8aa4 | |||
9ab8e08d59 | |||
677899d9ff | |||
72e35af39f | |||
2a61c9049f | |||
1158eba7ac | |||
22c5bf7630 | |||
4148266ed0 | |||
6e8e597ff5 | |||
7357417f48 | |||
91bf627275 | |||
55b57c736b | |||
dd5e3fba01 | |||
49a09ab7dd | |||
dae28f7f17 | |||
9cd76f122e | |||
920b5bb15d | |||
3611818eda | |||
7d83027954 | |||
ea190b6898 | |||
aa75d5458d | |||
4172a7c62e | |||
355b4706d3 | |||
eb1ffae01b | |||
cc0733a4fa | |||
c786bbbc5b | |||
f87b1c2fcd | |||
14fd53c915 | |||
aa2edcc6e5 | |||
6b6f010851 | |||
5e8805f24d | |||
3848944d35 | |||
9d7df45b7c | |||
7a164ed401 | |||
f530284031 | |||
38c0cf7007 | |||
f3598e6b0f | |||
291ca860af | |||
7d20871f0d | |||
6942b063ee | |||
e56bd27c1e | |||
a3beec6b9c | |||
04a1ecc4f4 | |||
7707814f2e | |||
4d4f2b62aa | |||
5abffe402f | |||
38ec32a146 | |||
d77ad42326 | |||
4106f0fa9e | |||
a0a0bf0577 | |||
71c7920d0f | |||
9bb1b01742 | |||
8c824680ce | |||
60b3f74be8 | |||
dfb09bf2ab | |||
98d6a43e1e | |||
49466d0d14 | |||
66cc9a075c | |||
1e10fc2e30 | |||
c8cf5f8c44 | |||
96e6c9cef2 | |||
931ee55e1d | |||
4d3aede5d3 | |||
0b1dd69b01 | |||
0947aa901e | |||
01e3d7952a | |||
84b224b9db | |||
39f8f6868a | |||
556915cab6 | |||
bff654b843 | |||
3a875e2954 | |||
bdb63ac785 | |||
9a5dc54f85 | |||
48524a58ff | |||
38bd49b97e | |||
28054a0be3 | |||
250a0863f6 | |||
b1764a6864 | |||
41f8f0113b | |||
db63e84a9f | |||
e0a4c58081 | |||
d2b47a5681 | |||
106e5c1f92 | |||
c00a9fae0c | |||
087bbd2e3e | |||
e16f2bb23d | |||
8d0bacf146 | |||
354f69b2f6 | |||
39e6b16069 | |||
b30272d896 | |||
755822bf14 | |||
99ffc26d40 | |||
4a8f032304 | |||
a0b775a7c0 | |||
0ab0bdf818 | |||
fce32ea5c7 | |||
8d3c77a0b9 | |||
00de73bdfc | |||
96197af3f1 | |||
dacde21c27 | |||
0d3b2ed230 | |||
fa4226c742 | |||
7cb4c42772 | |||
99f251451e | |||
d5f9a80b6c | |||
d324040adc | |||
da5eba17d8 | |||
434596b103 | |||
71a185c70e | |||
cbbb5f4ccb | |||
89ec25f718 | |||
e5b688214c | |||
225dbcce0a | |||
b22dc213e8 | |||
ad12a7264e | |||
29059b77a8 | |||
cdaa64a4b2 | |||
bc4296729f | |||
3a3630f3ef | |||
93ce747205 | |||
1493a4c815 | |||
54be6beaab | |||
e9fc9fdf12 | |||
ba4670eddc | |||
5a67d0ac84 | |||
be362f0d9f | |||
a394e6a3e3 | |||
1a5f1977c4 | |||
feee8ad72e | |||
c9e78c4f4a | |||
d0e2349dfd | |||
d516cbfe6c | |||
86fd5b4c97 | |||
1131a972cd | |||
2048f77178 | |||
a70c6f25ea | |||
490427f94d | |||
7cc91a8244 | |||
4f951a242b | |||
c095fc1eab | |||
c1182377db | |||
02473328e7 | |||
2b00cdf330 | |||
18cf49755e | |||
3a7de0be5c | |||
a1b610ee03 | |||
4d99b84e5b | |||
e20d13c44e | |||
18e9064d25 | |||
fad3038df2 | |||
8e4c4f8407 | |||
68bd24d065 | |||
d15a17b634 | |||
fa1090b6eb | |||
483ef486af | |||
175659a3dd | |||
dd85cbca39 | |||
22b97b7214 | |||
db68dd3bc1 | |||
85b9c19871 | |||
2bfc237e53 | |||
d74ea22d7d | |||
8004132a3a | |||
a6f4183cde | |||
51e9f3ede2 | |||
bfc7b3d183 | |||
8a348423ae | |||
e4952cd145 | |||
5b0bf5d150 | |||
79180dc021 | |||
599c95e5f6 | |||
e1ed8b71f6 | |||
6ca142bf20 | |||
6b20d2a5f3 | |||
bef55db120 | |||
3bb3658d7d | |||
a4034ce1e2 | |||
d9fc66fdbc | |||
3ebfd729cf | |||
6adb346cee | |||
318ff52ff3 | |||
b7b0f8f68d | |||
94bb7a1435 | |||
913a297e8d | |||
d469d426f8 | |||
ec05fbcf19 | |||
686faf0556 | |||
fe2d4e0d38 | |||
c500873586 | |||
fc788eb426 | |||
87eac1dc1a | |||
91d9b9811f | |||
71beb4b08f | |||
d26f06e2d1 | |||
dca08af003 | |||
4c740e26d7 | |||
131f581f77 | |||
9236a43a4d | |||
7f4eddf6d6 | |||
d1e631a487 | |||
0b78375211 | |||
15540764a0 | |||
82234cbbb2 | |||
22392daef7 | |||
7f3ae6edb0 | |||
1a993f5dfb | |||
4e527304d0 | |||
841be8d806 | |||
055cd01bb7 | |||
e34c364d5e | |||
926eb099f1 | |||
710508dc40 | |||
b4ea68b88a | |||
2bf9acd95e | |||
a8cb905255 | |||
567387aee0 | |||
5b71e3184a | |||
e1724444ac | |||
cf8940e80e | |||
fe1b982d13 | |||
221ae2427b | |||
29f780863b | |||
8aaca8e55c | |||
2dda3d2feb | |||
22ebaedb45 | |||
7065f00443 | |||
15732269da | |||
7b06be8f5e | |||
d2dcec40e1 | |||
2af6cc4d1b | |||
56c6174d61 | |||
66e914a8ab | |||
8ae9607d9b | |||
5c0297fb61 | |||
f5bf9a2cda | |||
987ab7612d | |||
a186d5f87a | |||
801e0f9ef7 | |||
874ea62dd5 | |||
ac20ddfc6c | |||
f0b991e1a8 | |||
adf385fdf3 | |||
7af6bc093d | |||
3708fa864b | |||
28276e1b37 | |||
b0efd685a9 | |||
422aacf8e6 | |||
f6576cce27 | |||
e068ee09ca | |||
d3b48cdd22 | |||
91e3bdff48 | |||
4299d1526b | |||
c26b36cf4f | |||
3095da64d7 | |||
07f961ecba | |||
8d9caaec71 | |||
91634d5c1c | |||
f5463c3d38 | |||
73b70393d4 | |||
3db6e185e0 | |||
d174ed75c7 | |||
513d261f10 | |||
4430befe90 | |||
acf425b6cf | |||
1c4eb4322b | |||
3f3fa61a51 | |||
ddf24039e8 | |||
98b35affd5 | |||
b3cc1e1af1 | |||
5b6a5f8aa9 | |||
3e6d2391f7 | |||
664ee9d82f | |||
c9cc3c9895 | |||
00c7e5c72b | |||
2b770ae2f8 | |||
558b31f4d9 | |||
174a5e7f13 | |||
952fcf5d09 | |||
c821f191b0 | |||
3322e564fd | |||
7bf5d557c1 | |||
0c1e06199c | |||
85a20b9a39 | |||
931a124349 | |||
ab52f4d91d | |||
f3182ef29b | |||
5641af437e | |||
1c8d3ded3d | |||
c2a445370e | |||
8e5355f2d9 | |||
2492157833 | |||
7c375e8fd9 | |||
53b5d8ac33 | |||
e5a8fb390e | |||
79cbae0c73 | |||
22b0b8b750 | |||
ddbddf6edf | |||
adcf58da68 | |||
05f6b79e29 | |||
649cb548d0 | |||
14db2343c9 | |||
67eb0c8de0 | |||
870f378782 | |||
82a58010f5 | |||
f652c58367 | |||
468d138be7 | |||
f409d2f435 | |||
5780a17794 | |||
9b765d23fa | |||
4476861d9f | |||
e12ddca1a5 | |||
084d00a156 | |||
404a73a712 | |||
3b2410d904 | |||
bd5009058b | |||
d3f79c7ad3 | |||
3f65503a79 | |||
6ac1216f8c | |||
1cae35f96b | |||
0d13e91a62 | |||
b1b600e09e | |||
3692e1c4bd | |||
dcbd82ac3b | |||
d4f0541027 | |||
a30d8e7819 | |||
8ee6bf044a | |||
6632247c9c | |||
d68389dc52 | |||
4a43273ee5 | |||
66f52a6e21 | |||
640bfc4eff | |||
408ef0f5b7 | |||
b9f76394aa | |||
a96f483d56 | |||
84cb9f15a4 | |||
d4da14cf18 | |||
4ad4b8e0b8 | |||
bb29d9c8ca | |||
e72e65858f | |||
a42845502e | |||
bea5ad3f13 | |||
5a0440d6f8 | |||
38b62d4ae3 | |||
462d8b3e74 | |||
291c3b6dbc | |||
df225d9170 | |||
592e981bd2 | |||
3d7c44735a | |||
81fddb4ccf | |||
c9d4c5ae3e | |||
be5b1fd92b | |||
d78c419627 | |||
dc52abf4ce | |||
a13549cc28 | |||
baf4c474e3 | |||
a58750992d | |||
17546c3a08 | |||
067f13b61c | |||
e249983c77 | |||
454b191370 | |||
a882a9d79f | |||
89fc835bb2 | |||
364958cbaf | |||
1b6af2045e | |||
be09ff8e43 | |||
99c8bffcbf | |||
03d16d12d5 | |||
1624c51cb5 | |||
83aabefcc5 | |||
dfece708e1 | |||
5d0f82ffbd | |||
361dc94002 | |||
cc0fdf15ef | |||
928675a847 | |||
12c1131b0c | |||
bb1dde0469 | |||
ced69b8397 | |||
013808956c | |||
009057cb87 | |||
82cb21fca3 | |||
7e8937a332 | |||
e5dcfa0a2e | |||
f4520a011a | |||
98dd6ca460 | |||
c3d9312240 | |||
5ea761e19f | |||
46a7860427 | |||
af9b63eaed | |||
9a26e0db16 | |||
efe6989fd3 | |||
aa1c9b80e3 | |||
6981df3b9a | |||
0d1ed625a8 | |||
710fc56c6a | |||
d5a15d6756 | |||
b376da1829 | |||
f7f17f0057 | |||
d06b9c2992 | |||
99ca5d0a03 | |||
4783c7f70a | |||
d89bdfbd27 | |||
1e324ad3bc | |||
52737e91e5 | |||
1872e2b63d | |||
3c5605b793 | |||
9a2b7cf5be | |||
1a20e9f9b4 | |||
14d79e4eef | |||
71f48d2aef | |||
312adca226 | |||
d35c6e77d7 | |||
1de21c86ae | |||
c709a592eb | |||
a54c544eb4 | |||
7d936ec6aa | |||
f63ec1332f | |||
d340ccd601 | |||
95e8f0a31e | |||
97ddfcb17a | |||
7bb5f9a1e4 | |||
11297b38c5 | |||
fc19ab2868 | |||
5e01c0a7db | |||
f1c3d820f7 | |||
0757a75732 | |||
f0ea45a0f8 | |||
45f2335a60 | |||
d629939cf3 | |||
404f76dcb9 | |||
498ce6b00c | |||
e3a8fd116d | |||
d33e09bcf3 | |||
fb3bad3887 | |||
3a736ad4a8 | |||
c1b0c41769 | |||
c03274703e | |||
4cd08e88f6 | |||
e2c4872030 | |||
d4f190e995 | |||
039107e837 | |||
ef6c211275 | |||
1f3accc0d7 | |||
2815f80063 | |||
fa645abee3 | |||
a86649def3 | |||
1fc4c56bc4 | |||
79dd72f53d | |||
ffa060ce56 | |||
5ce9719951 | |||
914aa7d372 | |||
4a88cbde3a | |||
4882519c0f | |||
7abe68fac1 | |||
e62cca1e7c | |||
a016741918 | |||
2f95810fa3 | |||
16e2c3b1e0 | |||
bc8a92caa9 | |||
3a5b67a3e1 | |||
2a596b8162 | |||
e059239bc3 | |||
986ad9fc57 | |||
1bb3d9be73 | |||
ae31f19ef6 | |||
c170ddc7ae | |||
58b6d92ce2 | |||
87a4d73556 | |||
4c54a003fa | |||
a5f3eabf8b | |||
3bf6c59d23 | |||
ef83dea95c | |||
686c23d25b | |||
b153e90ec5 | |||
38cc36980f | |||
b83fb525a8 | |||
e26e0955b3 | |||
7ada80b619 | |||
056e0fe2d9 | |||
9be0c67d5c | |||
664bc9cae0 | |||
959c7dc783 | |||
8e333d0a03 | |||
5afcf17706 | |||
a8d05294bc | |||
1b25e492c7 | |||
61b22316d6 | |||
be8ebdba46 | |||
2d759df47a | |||
d1b5cf99d0 | |||
516608d883 | |||
bf95e6def9 | |||
3c5cb31775 | |||
d2f51fccb9 | |||
c13db04f6d | |||
d3aa056151 | |||
1c60f0b53b | |||
ca2b85f453 | |||
b80479f9ef | |||
0a9070c394 | |||
bd29bac716 | |||
d42a22f446 | |||
d1112a0feb | |||
a73baded88 | |||
24d3a698a0 | |||
1eeba34806 | |||
94fa95d747 | |||
c98a561722 | |||
9f6484a328 | |||
40c0ed092e | |||
c719aa3db8 | |||
8f8f72fa76 | |||
4ae6d42871 | |||
64243382cf | |||
c7acb2d2c4 | |||
20795cf884 | |||
6b9f64a273 | |||
9e270c951a | |||
20308dc804 | |||
b1ecb1f61f | |||
6fd8979754 | |||
050416224d | |||
6e5a221180 | |||
a1ab252303 | |||
3c89fd51ee | |||
018b8a6315 | |||
ecaa146d5b | |||
f50a4d8c2a | |||
68b0e44fbd | |||
ac9946c697 | |||
a0a8bc24e8 | |||
06ab802bc6 | |||
04ec757083 | |||
15e04bb55d | |||
e4ed7fd8f7 | |||
fd5352b0c6 | |||
606e667b88 | |||
2a209c23c4 | |||
70305266dc | |||
8e561d9f95 | |||
f446cac43c | |||
7e1ceb9a3e | |||
1b5e35461d | |||
df75700015 | |||
b586df6689 | |||
4ca2ff0495 | |||
93494c7e35 | |||
11874bc4ae | |||
dcf98d13c8 | |||
2a735e815a | |||
52de16b4c9 | |||
7133a28fdb | |||
ade2ff97e0 | |||
450d86be7d | |||
c9caf612eb | |||
56ef678c09 | |||
29e647763a | |||
357150bcab | |||
f7224ff403 | |||
01ffad2e6e | |||
223e8cafac | |||
d1ffbd8a03 | |||
f286cb9a34 | |||
5c63855cc0 | |||
2a96ae9ec2 | |||
36a2da0659 | |||
38abec520c | |||
1274d26b4c | |||
6556c79207 | |||
7e6c580130 | |||
cc4fb64b34 | |||
f4cb4bb1b8 | |||
287b3ba1f4 | |||
208998972a | |||
7cdd062432 | |||
eccb529605 | |||
78dc28cce8 | |||
84076db78e | |||
c3779f0e94 | |||
c5ac563e74 | |||
92ca220890 | |||
72f88e5c0f | |||
1a75a71ad6 | |||
3c3b179c29 | |||
3f08bb4cdf | |||
423268f485 | |||
d3f003a15f | |||
7386378cc0 | |||
d6547462e5 | |||
d297a220ce | |||
1de5434e1a | |||
f46accc74d | |||
cd2100ed84 | |||
ac087921d8 | |||
82b1f14e2b | |||
df7e1cf078 | |||
39fa8f7be4 | |||
46c2184de4 | |||
a9f9894f29 | |||
a6c360eeda | |||
01a4002169 | |||
8caaf317ae | |||
0e3c2ef10f | |||
db6c85d3d7 | |||
2bd95620a5 | |||
d8ad30f38a | |||
aad5f52968 | |||
f5d49f6657 | |||
53ae64e578 | |||
1a936b6aca | |||
4776fa1361 | |||
c5084fd025 | |||
cc2735f733 | |||
7f6b2b80f8 | |||
f64c2bc065 | |||
6752b49536 | |||
ab138e7df1 | |||
059da90a96 | |||
0821c7bdd9 | |||
89e00eb5a4 | |||
1a0f347023 | |||
1e27c2dabe | |||
629be45c4a | |||
e115e3c4e7 | |||
414fb1f406 | |||
fe0a8f3363 | |||
45589d5133 | |||
7804787e9e | |||
2e735f622f | |||
6accb90c47 | |||
e948a013cd | |||
b79535f369 | |||
ed3bcc6d9a | |||
0f23581f64 | |||
2af1e4b192 | |||
dc404b365f | |||
86f3891a2b | |||
86053ea54b | |||
938600ba95 | |||
80ab967d39 | |||
43acbaa702 | |||
5d6492e6f5 | |||
aeb9cc1732 | |||
fa25c8ef22 | |||
77a9613c3a | |||
ba62a1f630 | |||
153ab8f0fa | |||
f6c860afc0 | |||
d13b755df2 | |||
6bacbf6cac | |||
0d5baa2219 | |||
97c8a1d7ab | |||
5923d22379 | |||
70494117d1 | |||
8210743dad | |||
895f3cc109 | |||
71f160dddc | |||
92abaa0d47 | |||
47710c1385 | |||
df3abcbc9a | |||
dbb7ad41e5 | |||
9773d4e409 | |||
993165fa66 | |||
c49f5dad05 | |||
c0bdedfed3 | |||
061107b65f | |||
7bf421f847 | |||
cb0c1d34a2 | |||
749b381f26 | |||
d89279d708 | |||
be209ed30c | |||
4a4ba2791d | |||
c61d9776e7 | |||
b5716abd3e | |||
b9bb78d04b | |||
8a39ee65cd | |||
301a463aeb | |||
d1b0bece47 | |||
63fd7d1d63 | |||
f4fb2518a1 | |||
ee486de947 | |||
c1a12a58eb | |||
c3aadab615 | |||
26774d2317 | |||
61def880db | |||
11a6331185 | |||
378509cef4 | |||
4a1fa03b2d | |||
52bff85dda | |||
e5b0b34604 | |||
0a0063fa27 | |||
bf1f6f663a | |||
8bac454792 | |||
7eaf09b3da | |||
378a261e64 | |||
53c99f7469 | |||
f93e618f67 | |||
64b78461f6 | |||
2f5c9273ee | |||
38371234a2 | |||
10cb606578 | |||
87caf458df | |||
4ff4e4e626 | |||
9053f9bb98 | |||
b6b72c861f | |||
478eed6603 | |||
6b76f64b48 | |||
53a2787626 | |||
cac9927395 | |||
9e14619a0b | |||
c0dd4c3209 | |||
d82e1342fb | |||
720912e880 | |||
6f47434833 | |||
6f13a2c0c7 | |||
b7a150bc64 | |||
4d22c45b76 | |||
2a76a717e6 | |||
b3b658a955 | |||
c8c0d208be | |||
04dd41ac3b | |||
10815eca8e | |||
06d2f343dd | |||
a6c5e85ae7 | |||
45d6a326cd | |||
0332e32293 | |||
2a3a34a80c | |||
68da47b59a | |||
b1f0f048cd | |||
a7b4463f86 | |||
ee60adc45a | |||
36338b4928 | |||
23d3c512c2 | |||
4144638be4 | |||
f2320ee648 | |||
17afa3e672 | |||
5b2c355c38 | |||
61d54903e3 | |||
c1078c4374 | |||
4e427b5a9e | |||
227ec71db3 | |||
d047b8daa1 | |||
c2009b71b1 | |||
ba8629e2ac | |||
6aba453afb | |||
a15578a8f6 | |||
5c8d9f4eb9 | |||
a9e615b3c7 | |||
94ad21020c | |||
4b76cb4318 | |||
fad7ec6b7f | |||
82a49a8e89 | |||
2bcc5a2ac7 | |||
4f044cf2f9 | |||
9a407f79ff | |||
affec30c64 | |||
d050e60da2 | |||
866b9835a6 | |||
f6564909aa | |||
315e8b64b8 | |||
f99f634816 | |||
5292a5b9d4 | |||
cf22d62a74 | |||
9363e2ab83 | |||
e5ddd92677 | |||
04628056af | |||
dada86c0b0 | |||
92c269c972 | |||
6991e3c99b | |||
3ee3daee00 | |||
85fcff4cf7 | |||
30db47d9b6 | |||
4d2c85ffdc | |||
e36433c23a | |||
8486766a60 | |||
ef72d355d6 | |||
7d013ad5e8 | |||
5fcce6567e | |||
00af537b0d | |||
78449fa62f | |||
ab0d648a03 | |||
43d2107493 | |||
fd8b4a3305 | |||
79dc4f9a70 | |||
b0fa11b8b8 | |||
6e7bb93fd6 | |||
e1448eb238 | |||
585aeb8f0b | |||
563823189a | |||
e9bf916a74 | |||
bcc5f24c0f | |||
9462c2e476 | |||
af41c79798 | |||
733cbb5304 | |||
d5e1d2efd5 | |||
bb072a1f8f | |||
8737530a7d | |||
dd160dc342 | |||
4a9e82903e | |||
1d040dbdd2 | |||
e4db9c72dd | |||
6308ce2740 | |||
87bad71bec | |||
50f09c8e4d | |||
bb1ecdd3c9 | |||
a2c3e6e405 | |||
cddbb44c75 | |||
7aa0c91401 | |||
6bfc849a24 | |||
ac4aa0d182 | |||
d9ffc39075 | |||
87e8393b07 | |||
1ab9c82dfb | |||
6e484e5c2d | |||
087b68e14d | |||
c313950891 | |||
7716d3377a | |||
0cbe34eef3 | |||
08d8c334a3 | |||
d75a151df3 | |||
10e223ede2 | |||
6a8bacf01c | |||
d4cc3900bd | |||
ab619a4a3f | |||
4c447985b6 | |||
eaadd2d0cd | |||
9830086790 | |||
8393746e02 | |||
2314ad9bf9 | |||
3af21612b6 | |||
7674a82801 | |||
d63d2a8a26 | |||
a458018aa2 | |||
33cde6aacd | |||
4ded2682d2 | |||
4042938556 | |||
0e683cc535 | |||
4923da7f4d | |||
11781087ca | |||
3063251d43 | |||
b42b170ad2 | |||
defbb44b35 | |||
a00eb81f03 | |||
a63d989a35 | |||
6c3c5578c6 | |||
122783e36b | |||
b84b95fe97 | |||
a99010b8c2 | |||
8954aa7118 | |||
3cf848958f | |||
1a5668377c | |||
dc10c56b35 | |||
331cd173ce | |||
1881d5eeed | |||
e0872b6157 | |||
63fb9c7135 | |||
9964654495 | |||
ae275c9e60 | |||
4277fe2fdb | |||
7acc2beae0 | |||
847deeac79 | |||
ac56c1310c | |||
7460b343fe | |||
ec16011e31 | |||
71b0e27517 | |||
60e9282f0a | |||
6cd35a50ce | |||
b35ad76ec6 | |||
54208f6fc3 | |||
6282bf33a0 | |||
a1c1958235 | |||
91b699fbe0 | |||
3a08655b06 | |||
9a9c8e5709 | |||
c7d34b54aa | |||
8d860c84c8 | |||
1dc086730e | |||
5d79e56d30 | |||
6e7677de79 | |||
fab6b8be3c | |||
f1c1eed437 | |||
348ab794c9 | |||
aacedcc4b3 | |||
786acc961a | |||
7adffdbd78 | |||
e3b519cdd8 | |||
e9c23195a0 | |||
c6c3af8099 | |||
07c077cf94 | |||
4ac18f1989 | |||
4ecb919787 | |||
4152bd5e26 | |||
a8cc26fd91 | |||
81cb00573f | |||
c22598c8ff | |||
bb3b9f61cd | |||
49cd7f799e | |||
8b334551d8 | |||
5ef6d53d00 | |||
901c9b29bc | |||
2d79c500df | |||
d3598021b7 | |||
31e0340959 | |||
cb46e8751b | |||
739a836c52 | |||
1cbe00d613 | |||
10d92ca176 | |||
257dbd188f | |||
38cc0579a6 | |||
a9c8cda5ec | |||
06654ff3a6 | |||
f1b62b45f4 | |||
8adadaa5d4 | |||
35070f7c1c | |||
a0b15a0efd | |||
b906e9361f | |||
ec2d7efe0e | |||
81e9fdfe75 | |||
465bb133c7 | |||
c15d7e03b4 | |||
5bfcfeb779 | |||
faa7fd0f05 | |||
ab50b10d1b | |||
b7a71edfcb | |||
587b17c120 | |||
c46ffed846 | |||
707b6f9a95 | |||
4bdc704a25 | |||
c0fd700904 | |||
72177c676e | |||
784fd74d3f | |||
cfbd43d1ee | |||
f10bbd8c69 | |||
6bcb6f92f5 | |||
f6b5684a5b | |||
866e8db5f7 | |||
a9925c7521 | |||
f955cc33c5 | |||
e728f32a15 | |||
4abb4c6489 | |||
66998e60b8 | |||
71288e5799 | |||
8fdd0b20d1 | |||
4e9ff45747 | |||
d6e28a923c | |||
1604786285 | |||
35cb9100cd | |||
4729e3e999 | |||
b0e66a4aa6 | |||
4218467ab3 | |||
6e62625ebf | |||
c8a0a83e2b | |||
76bd04e349 | |||
a8a78b8ea3 | |||
3435ebfe42 | |||
4d485e1b6b | |||
3f905ee7d0 | |||
e90cb6b53b | |||
400655f212 | |||
481a4b2096 | |||
85bbd49798 | |||
40391c57c2 | |||
7607eb173b | |||
15318c4631 | |||
7be566ef7c | |||
3c9ec55f0a | |||
5ee6981410 | |||
c32f82baee | |||
89bb1ae835 | |||
9387235a04 | |||
7766d0ddaa | |||
cdade5f649 | |||
de0a57ec76 | |||
6e1a0554c0 | |||
ae73d08d67 |
@ -1,3 +1,3 @@
|
||||
dist/
|
||||
vendor/
|
||||
!dist/traefik
|
||||
site/
|
||||
|
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
# vendor/github.com/go-acme/lego/providers/dns/cloudxns/cloudxns.go eol=crlf
|
24
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
provider/kubernetes/** @containous/kubernetes
|
||||
provider/rancher/** @containous/rancher
|
||||
provider/marathon/** @containous/marathon
|
||||
provider/docker/** @containous/docker
|
||||
|
||||
docs/user-guide/kubernetes.md @containous/kubernetes
|
||||
docs/user-guide/marathon.md @containous/marathon
|
||||
docs/user-guide/swarm.md @containous/docker
|
||||
docs/user-guide/swarm-mode.md @containous/docker
|
||||
|
||||
docs/configuration/backends/docker.md @containous/docker
|
||||
docs/configuration/backends/kubernetes.md @containous/kubernetes
|
||||
docs/configuration/backends/marathon.md @containous/marathon
|
||||
docs/configuration/backends/rancher.md @containous/rancher
|
||||
|
||||
examples/k8s/ @containous/kubernetes
|
||||
examples/compose-k8s.yaml @containous/kubernetes
|
||||
examples/k8s.namespace.yaml @containous/kubernetes
|
||||
examples/compose-rancher.yml @containous/rancher
|
||||
examples/compose-marathon.yml @containous/marathon
|
||||
|
||||
vendor/github.com/gambol99/go-marathon @containous/marathon
|
||||
vendor/github.com/rancher @containous/rancher
|
||||
vendor/k8s.io/ @containous/kubernetes
|
82
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
|
||||
The issue tracker is for reporting bugs and feature requests only.
|
||||
For end-user related support questions, please refer to one of the following:
|
||||
|
||||
- the Traefik community forum: https://community.containo.us/
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
<!--
|
||||
If you intend to ask a support question: DO NOT FILE AN ISSUE.
|
||||
-->
|
||||
|
||||
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
|
||||
<!--
|
||||
|
||||
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
|
||||
-->
|
||||
|
||||
### What did you do?
|
||||
|
||||
<!--
|
||||
|
||||
HOW TO WRITE A GOOD ISSUE?
|
||||
|
||||
- Respect the issue template as much as possible.
|
||||
- The title should be short and descriptive.
|
||||
- Explain the conditions which led you to report this issue: the context.
|
||||
- The context should lead to something, an idea or a problem that 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
|
||||
|
||||
For the alpine Traefik Docker image:
|
||||
docker run [IMAGE] traefik version
|
||||
ex: docker run traefik traefik version
|
||||
-->
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
|
||||
|
||||
```toml
|
||||
# (paste your configuration here)
|
||||
```
|
||||
<!--
|
||||
Add more configuration information here.
|
||||
-->
|
||||
|
||||
|
||||
### If applicable, please paste the log output at DEBUG level (`--log.level=DEBUG` switch)
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
87
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
|
||||
The issue tracker is for reporting bugs and feature requests only.
|
||||
For end-user related support questions, please refer to one of the following:
|
||||
|
||||
- the Traefik community forum: https://community.containo.us/
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### Do you want to request a *feature* or report a *bug*?
|
||||
|
||||
Bug
|
||||
|
||||
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
|
||||
<!--
|
||||
|
||||
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||
|
||||
-->
|
||||
|
||||
### What did you do?
|
||||
|
||||
<!--
|
||||
|
||||
HOW TO WRITE A GOOD BUG REPORT?
|
||||
|
||||
- Respect the issue template as much as possible.
|
||||
- The title should be short and descriptive.
|
||||
- Explain the conditions which led you to report this issue: the context.
|
||||
- The context should lead to something, an idea or a problem that 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
|
||||
|
||||
For the alpine Traefik Docker image:
|
||||
docker run [IMAGE] traefik version
|
||||
ex: docker run traefik traefik version
|
||||
-->
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
|
||||
|
||||
```toml
|
||||
# (paste your configuration here)
|
||||
```
|
||||
|
||||
<!--
|
||||
Add more configuration information here.
|
||||
-->
|
||||
|
||||
|
||||
### If applicable, please paste the log output in DEBUG level (`--log.level=DEBUG` switch)
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
35
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
|
||||
|
||||
The issue tracker is for reporting bugs and feature requests only.
|
||||
For end-user related support questions, please refer to one of the following:
|
||||
|
||||
- the Traefik community forum: https://community.containo.us/
|
||||
|
||||
-->
|
||||
|
||||
|
||||
### 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.
|
||||
- The title should be short and descriptive.
|
||||
- Explain the conditions which led you to report this issue: the context.
|
||||
- The context should lead to something, an idea or a problem that 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
|
||||
|
||||
-->
|
36
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<!--
|
||||
PLEASE READ THIS MESSAGE.
|
||||
|
||||
HOW TO WRITE A GOOD PULL REQUEST?
|
||||
|
||||
- Make it small.
|
||||
- Do only one thing.
|
||||
- Avoid re-formatting.
|
||||
- Make sure the code builds.
|
||||
- Make sure all tests pass.
|
||||
- Add tests.
|
||||
- Write useful descriptions and titles.
|
||||
- Address review comments in terms of additional commits.
|
||||
- Do not amend/squash existing ones unless the PR is trivial.
|
||||
- Read the contributing guide: https://github.com/containous/traefik/blob/master/CONTRIBUTING.md.
|
||||
|
||||
-->
|
||||
|
||||
### What does this PR do?
|
||||
|
||||
<!-- A brief description of the change being made with this pull request. -->
|
||||
|
||||
|
||||
### Motivation
|
||||
|
||||
<!-- What inspired you to submit this pull request? -->
|
||||
|
||||
|
||||
### More
|
||||
|
||||
- [ ] Added/updated tests
|
||||
- [ ] Added/updated documentation
|
||||
|
||||
### Additional Notes
|
||||
|
||||
<!-- Anything else we should know when reviewing? -->
|
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
@ -0,0 +1,7 @@
|
||||
### What does this PR do?
|
||||
|
||||
Prepare release v{{.Version}}.
|
||||
|
||||
### Motivation
|
||||
|
||||
Create a new release.
|
23
.gitignore
vendored
@ -1,9 +1,18 @@
|
||||
/dist
|
||||
gen.go
|
||||
.idea
|
||||
log
|
||||
.idea/
|
||||
.intellij/
|
||||
*.iml
|
||||
traefik
|
||||
traefik.toml
|
||||
|
||||
.vscode/
|
||||
.DS_Store
|
||||
/dist
|
||||
/webui/.tmp/
|
||||
/site/
|
||||
/docs/site/
|
||||
/static/
|
||||
/autogen/
|
||||
/traefik
|
||||
/traefik.toml
|
||||
/traefik.yml
|
||||
*.log
|
||||
*.exe
|
||||
cover.out
|
||||
vendor/
|
||||
|
90
.golangci.toml
Normal file
@ -0,0 +1,90 @@
|
||||
[run]
|
||||
deadline = "10m"
|
||||
skip-files = []
|
||||
|
||||
[linters-settings]
|
||||
|
||||
[linters-settings.govet]
|
||||
check-shadowing = false
|
||||
|
||||
[linters-settings.golint]
|
||||
min-confidence = 0.0
|
||||
|
||||
[linters-settings.gocyclo]
|
||||
min-complexity = 14.0
|
||||
|
||||
[linters-settings.maligned]
|
||||
suggest-new = true
|
||||
|
||||
[linters-settings.goconst]
|
||||
min-len = 3.0
|
||||
min-occurrences = 4.0
|
||||
|
||||
[linters-settings.misspell]
|
||||
locale = "US"
|
||||
|
||||
[linters-settings.funlen]
|
||||
lines = 230 # default 60
|
||||
statements = 120 # default 40
|
||||
|
||||
[linters]
|
||||
enable-all = true
|
||||
disable = [
|
||||
"gocyclo", # FIXME must be fixed
|
||||
"gosec",
|
||||
"dupl",
|
||||
"maligned",
|
||||
"lll",
|
||||
"unparam",
|
||||
"prealloc",
|
||||
"scopelint",
|
||||
"gochecknoinits",
|
||||
"gochecknoglobals",
|
||||
"bodyclose", # Too many false-positive and panics.
|
||||
]
|
||||
|
||||
[issues]
|
||||
exclude-use-default = false
|
||||
max-per-linter = 0
|
||||
max-same-issues = 0
|
||||
exclude = [
|
||||
"SA1019: http.CloseNotifier is deprecated: the CloseNotifier interface predates Go's context package. New code should use Request.Context instead.", # FIXME must be fixed
|
||||
"Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
|
||||
"should have a package comment, unless it's in another file for this package",
|
||||
]
|
||||
[[issues.exclude-rules]]
|
||||
path = "(.+)_test.go"
|
||||
linters = ["goconst", "funlen"]
|
||||
[[issues.exclude-rules]]
|
||||
path = "integration/.+_test.go"
|
||||
text = "Error return value of `cmd\\.Process\\.Kill` is not checked"
|
||||
[[issues.exclude-rules]]
|
||||
path = "integration/(consul_catalog_test|constraint_test).go"
|
||||
text = "Error return value of `(s.deregisterService|s.deregisterAgentService)` is not checked"
|
||||
[[issues.exclude-rules]]
|
||||
path = "integration/grpc_test.go"
|
||||
text = "Error return value of `closer` is not checked"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/h2c/h2c.go"
|
||||
text = "Error return value of `rw.Write` is not checked"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/middlewares/recovery/recovery.go"
|
||||
text = "`logger` can be `github.com/stretchr/testify/assert.TestingT`"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/provider/docker/builder_test.go"
|
||||
text = "(U1000: func )?`(.+)` is unused"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/provider/kubernetes/builder_(endpoint|service)_test.go"
|
||||
text = "(U1000: func )?`(.+)` is unused"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/config/parser/.+_test.go"
|
||||
text = "U1000: field `(foo|fuu)` is unused"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/server/service/bufferpool.go"
|
||||
text = "SA6002: argument should be pointer-like to avoid allocations"
|
||||
[[issues.exclude-rules]]
|
||||
path = "cmd/configuration.go"
|
||||
text = "string `traefik` has (\\d) occurrences, make it a constant"
|
||||
[[issues.exclude-rules]] # FIXME must be fixed
|
||||
path = "cmd/context.go"
|
||||
text = "S1000: should use a simple channel send/receive instead of `select` with a single case"
|
58
.goreleaser.yml
Normal file
@ -0,0 +1,58 @@
|
||||
project_name: traefik
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go generate
|
||||
|
||||
builds:
|
||||
- binary: traefik
|
||||
|
||||
main: ./cmd/traefik/traefik.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- -s -w -X github.com/containous/traefik/v2/pkg/version.Version={{.Version}} -X github.com/containous/traefik/v2/pkg/version.Codename={{.Env.CODENAME}} -X github.com/containous/traefik/v2/pkg/version.BuildDate={{.Date}}
|
||||
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
- freebsd
|
||||
- openbsd
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
- arm
|
||||
- arm64
|
||||
- ppc64le
|
||||
goarm:
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
- goos: openbsd
|
||||
goarch: arm
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
|
||||
changelog:
|
||||
skip: true
|
||||
|
||||
archives:
|
||||
- id: traefik
|
||||
name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
format: tar.gz
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- LICENSE.md
|
||||
- CHANGELOG.md
|
||||
|
||||
checksum:
|
||||
name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt"
|
||||
|
||||
release:
|
||||
disable: true
|
4
.semaphoreci/cleanup.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
sudo rm -rf static
|
20
.semaphoreci/golang.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
curl -O https://dl.google.com/go/go"${GO_VERSION}".linux-amd64.tar.gz
|
||||
|
||||
tar -xvf go"${GO_VERSION}".linux-amd64.tar.gz
|
||||
rm -rf go"${GO_VERSION}".linux-amd64.tar.gz
|
||||
|
||||
sudo mkdir -p /usr/local/golang/"${GO_VERSION}"/go
|
||||
sudo mv go /usr/local/golang/"${GO_VERSION}"/
|
||||
|
||||
sudo rm /usr/local/bin/go
|
||||
sudo chmod +x /usr/local/golang/"${GO_VERSION}"/go/bin/go
|
||||
sudo ln -s /usr/local/golang/"${GO_VERSION}"/go/bin/go /usr/local/bin/go
|
||||
|
||||
export GOROOT="/usr/local/golang/${GO_VERSION}/go"
|
||||
export GOTOOLDIR="/usr/local/golang/${GO_VERSION}/go/pkg/tool/linux_amd64"
|
||||
|
||||
go version
|
6
.semaphoreci/job1.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [ -n "$SHOULD_TEST" ]; then ci_retry make pull-images; fi
|
||||
|
||||
if [ -n "$SHOULD_TEST" ]; then ci_retry make test-integration; fi
|
8
.semaphoreci/job2.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
ci_retry make validate
|
||||
|
||||
if [ -n "$SHOULD_TEST" ]; then ci_retry make test-unit; fi
|
||||
|
||||
if [ -n "$SHOULD_TEST" ]; then make -j"${N_MAKE_JOBS}" crossbinary-default-parallel; fi
|
35
.semaphoreci/setup.sh
Executable file
@ -0,0 +1,35 @@
|
||||
# For personnal CI
|
||||
# mv /home/runner/workspace/src/github.com/<username>/ /home/runner/workspace/src/github.com/containous/
|
||||
# cd /home/runner/workspace/src/github.com/containous/traefik/
|
||||
for s in apache2 cassandra elasticsearch memcached mysql mongod postgresql sphinxsearch rethinkdb rabbitmq-server redis-server; do sudo service $s stop; done
|
||||
sudo swapoff -a
|
||||
sudo dd if=/dev/zero of=/swapfile bs=1M count=3072
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
sudo rm -rf /home/runner/.rbenv
|
||||
sudo rm -rf /usr/local/golang/{1.4.3,1.5.4,1.6.4,1.7.6,1.8.6,1.9.7,1.10.3,1.11}
|
||||
#export DOCKER_VERSION=18.06.3
|
||||
source .semaphoreci/vars
|
||||
if [ -z "${PULL_REQUEST_NUMBER}" ]; then SHOULD_TEST="-*-"; else TEMP_STORAGE=$(curl --silent https://patch-diff.githubusercontent.com/raw/containous/traefik/pull/${PULL_REQUEST_NUMBER}.diff | patch --dry-run -p1 -R || true); fi
|
||||
echo ${SHOULD_TEST}
|
||||
if [ -n "$TEMP_STORAGE" ]; then SHOULD_TEST=$(echo "$TEMP_STORAGE" | grep -Ev '(.md|.yaml|.yml)' || :); fi
|
||||
echo ${TEMP_STORAGE}
|
||||
echo ${SHOULD_TEST}
|
||||
#if [ -n "$SHOULD_TEST" ]; then sudo -E apt-get -yq update; fi
|
||||
#if [ -n "$SHOULD_TEST" ]; then sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*; fi
|
||||
if [ -n "$SHOULD_TEST" ]; then docker version; fi
|
||||
export GO_VERSION=1.12
|
||||
if [ -f "./go.mod" ]; then GO_VERSION="$(grep '^go .*' go.mod | awk '{print $2}')"; export GO_VERSION; fi
|
||||
#if [ "${GO_VERSION}" == '1.13' ]; then export GO_VERSION=1.13rc2; fi
|
||||
echo "Selected Go version: ${GO_VERSION}"
|
||||
|
||||
if [ -f "./.semaphoreci/golang.sh" ]; then ./.semaphoreci/golang.sh; fi
|
||||
if [ -f "./.semaphoreci/golang.sh" ]; then export GOROOT="/usr/local/golang/${GO_VERSION}/go"; fi
|
||||
if [ -f "./.semaphoreci/golang.sh" ]; then export GOTOOLDIR="/usr/local/golang/${GO_VERSION}/go/pkg/tool/linux_amd64"; fi
|
||||
go version
|
||||
|
||||
if [ -f "./go.mod" ]; then export GO111MODULE=on; fi
|
||||
if [ -f "./go.mod" ]; then export GOPROXY=https://proxy.golang.org; fi
|
||||
if [ -f "./go.mod" ]; then go mod download; fi
|
||||
|
||||
df
|
36
.semaphoreci/vars
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
export REPO='containous/traefik'
|
||||
|
||||
if VERSION=$(git describe --exact-match --abbrev=0 --tags);
|
||||
then
|
||||
export VERSION
|
||||
else
|
||||
export VERSION=''
|
||||
fi
|
||||
|
||||
export CODENAME=montdor
|
||||
|
||||
export N_MAKE_JOBS=2
|
||||
|
||||
|
||||
function ci_retry {
|
||||
|
||||
local NRETRY=3
|
||||
local NSLEEP=5
|
||||
local n=0
|
||||
|
||||
until [ $n -ge $NRETRY ]
|
||||
do
|
||||
"$@" && break
|
||||
n=$((n+1))
|
||||
echo "${*} failed, attempt ${n}/${NRETRY}"
|
||||
sleep $NSLEEP
|
||||
done
|
||||
|
||||
[ $n -lt $NRETRY ]
|
||||
|
||||
}
|
||||
|
||||
export -f ci_retry
|
58
.travis.yml
Normal file
@ -0,0 +1,58 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
git:
|
||||
depth: false
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- REPO=$TRAVIS_REPO_SLUG
|
||||
- VERSION=$TRAVIS_TAG
|
||||
- CODENAME=montdor
|
||||
- GO111MODULE=on
|
||||
|
||||
script:
|
||||
- echo "Skipping tests... (Tests are executed on SemaphoreCI)"
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make docs; fi
|
||||
|
||||
before_deploy:
|
||||
- >
|
||||
if ! [ "$BEFORE_DEPLOY_RUN" ]; then
|
||||
export BEFORE_DEPLOY_RUN=1;
|
||||
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;
|
||||
make build-image;
|
||||
if [ "$TRAVIS_TAG" ]; then
|
||||
make release-packages;
|
||||
fi;
|
||||
curl -sfL https://raw.githubusercontent.com/containous/structor/master/godownloader.sh | bash -s -- -b "${GOPATH}/bin" ${STRUCTOR_VERSION}
|
||||
structor -o containous -r traefik --dockerfile-url="https://raw.githubusercontent.com/containous/traefik/v1.7/docs.Dockerfile" --menu.js-url="https://raw.githubusercontent.com/containous/structor/master/traefik-menu.js.gotmpl" --rqts-url="https://raw.githubusercontent.com/containous/structor/master/requirements-override.txt" --force-edit-url --exp-branch=master --debug;
|
||||
fi
|
||||
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key: ${GITHUB_TOKEN}
|
||||
file: dist/traefik*
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
tags: true
|
||||
- provider: script
|
||||
script: sh script/deploy.sh
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
tags: true
|
||||
- provider: pages
|
||||
edge: false
|
||||
github_token: ${GITHUB_TOKEN}
|
||||
local_dir: site
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: containous/traefik
|
||||
all_branches: true
|
BIN
.travis/traefiker_rsa.enc
Normal file
4032
CHANGELOG.md
Normal file
51
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,51 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience,nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||
Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@containo.us
|
||||
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
|
||||
The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
3
CONTRIBUTING.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Contributing
|
||||
|
||||
See <https://docs.traefik.io/v2.0/contributing/thank-you/>.
|
@ -1,4 +1,6 @@
|
||||
FROM scratch
|
||||
COPY script/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY dist/traefik /
|
||||
EXPOSE 80
|
||||
VOLUME ["/tmp"]
|
||||
ENTRYPOINT ["/traefik"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Emile Vauge, emile@vauge.com
|
||||
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
|
||||
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE.
|
||||
|
183
Makefile
@ -1,68 +1,151 @@
|
||||
.PHONY: all
|
||||
.PHONY: all docs docs-serve
|
||||
|
||||
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/')
|
||||
|
||||
TAG_NAME := $(shell git tag -l --contains HEAD)
|
||||
SHA := $(shell git rev-parse HEAD)
|
||||
VERSION_GIT := $(if $(TAG_NAME),$(TAG_NAME),$(SHA))
|
||||
VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT))
|
||||
|
||||
BIND_DIR := "dist"
|
||||
|
||||
GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
|
||||
TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(subst /,-,$(GIT_BRANCH)))
|
||||
|
||||
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
|
||||
|
||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
|
||||
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
|
||||
|
||||
TRAEFIK_ENVS := \
|
||||
-e OS_ARCH_ARG \
|
||||
-e OS_PLATFORM_ARG \
|
||||
-e TESTFLAGS
|
||||
-e TESTFLAGS \
|
||||
-e VERBOSE \
|
||||
-e VERSION \
|
||||
-e CODENAME \
|
||||
-e TESTDIRS \
|
||||
-e CI \
|
||||
-e CONTAINER=DOCKER # Indicator for integration tests that we are running inside a container.
|
||||
|
||||
BIND_DIR := "dist"
|
||||
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/emilevauge/traefik/$(BIND_DIR)"
|
||||
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
|
||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) -it $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) -i $(DOCKER_RUN_OPTS)
|
||||
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"emilevauge/traefik")
|
||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -v "/var/run/docker.sock:/var/run/docker.sock")
|
||||
|
||||
DOCKER_RUN_TRAEFIK := docker run $(if $(CIRCLECI),,--rm) $(INTEGRATION_OPTS) -it $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
|
||||
print-%: ; @echo $*=$($*)
|
||||
PRE_TARGET ?= build-dev-image
|
||||
|
||||
default: binary
|
||||
|
||||
all: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh
|
||||
## Build Dev Docker image
|
||||
build-dev-image: dist
|
||||
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||
|
||||
binary: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary
|
||||
|
||||
crossbinary: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate crossbinary
|
||||
|
||||
test: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
|
||||
|
||||
test-unit: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit
|
||||
|
||||
test-integration: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-integration
|
||||
|
||||
validate: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-gofmt validate-govet
|
||||
|
||||
validate-gofmt: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-gofmt
|
||||
|
||||
validate-govet: build
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-govet
|
||||
|
||||
build: dist
|
||||
docker build -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||
|
||||
build-no-cache: dist
|
||||
## Build Dev Docker image without cache
|
||||
build-dev-image-no-cache: dist
|
||||
docker build --no-cache -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||
|
||||
shell: build
|
||||
$(DOCKER_RUN_TRAEFIK) /bin/bash
|
||||
|
||||
image: build
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
|
||||
## Create the "dist" directory
|
||||
dist:
|
||||
mkdir dist
|
||||
|
||||
## Build WebUI Docker image
|
||||
build-webui-image:
|
||||
docker build -t traefik-webui -f webui/Dockerfile webui
|
||||
|
||||
## Generate WebUI
|
||||
generate-webui: build-webui-image
|
||||
if [ ! -d "static" ]; then \
|
||||
mkdir -p static; \
|
||||
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build:nc; \
|
||||
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ../static; \
|
||||
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
||||
fi
|
||||
|
||||
## Build the linux binary
|
||||
binary: generate-webui $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate binary
|
||||
|
||||
## Build the binary for the standard plaforms (linux, darwin, windows)
|
||||
crossbinary-default: generate-webui build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
|
||||
|
||||
## Build the binary for the standard plaforms (linux, darwin, windows) in parallel
|
||||
crossbinary-default-parallel:
|
||||
$(MAKE) generate-webui
|
||||
$(MAKE) build-dev-image crossbinary-default
|
||||
|
||||
## Run the unit and integration tests
|
||||
test: build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
|
||||
|
||||
## Run the unit tests
|
||||
test-unit: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate test-unit
|
||||
|
||||
## Pull all images for integration tests
|
||||
pull-images:
|
||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
|
||||
|
||||
## Run the integration tests
|
||||
test-integration: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK),TEST_CONTAINER=1) ./script/make.sh generate binary test-integration
|
||||
TEST_HOST=1 ./script/make.sh test-integration
|
||||
|
||||
## Validate code and docs
|
||||
validate-files: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell
|
||||
bash $(CURDIR)/script/validate-shell-script.sh
|
||||
|
||||
## Validate code, docs, and vendor
|
||||
validate: $(PRE_TARGET)
|
||||
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell validate-vendor
|
||||
bash $(CURDIR)/script/validate-shell-script.sh
|
||||
|
||||
## Clean up static directory and build a Docker Traefik image
|
||||
build-image: binary
|
||||
rm -rf static
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
|
||||
## Build a Docker Traefik image
|
||||
build-image-dirty: binary
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
|
||||
## Start a shell inside the build env
|
||||
shell: build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK) /bin/bash
|
||||
|
||||
## Build documentation site
|
||||
docs:
|
||||
make -C ./docs docs
|
||||
|
||||
## Serve the documentation site localy
|
||||
docs-serve:
|
||||
make -C ./docs docs-serve
|
||||
|
||||
## Generate CRD clientset
|
||||
generate-crd:
|
||||
./script/update-generated-crd-code.sh
|
||||
|
||||
## Create packages for the release
|
||||
release-packages: generate-webui build-dev-image
|
||||
rm -rf dist
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
||||
--exclude-vcs \
|
||||
--exclude .idea \
|
||||
--exclude .travis \
|
||||
--exclude .semaphoreci \
|
||||
--exclude .github \
|
||||
--exclude dist .
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) chown -R $(shell id -u):$(shell id -g) dist/
|
||||
|
||||
## Format the Code
|
||||
fmt:
|
||||
gofmt -s -l -w $(SRCS)
|
||||
|
||||
run-dev:
|
||||
go generate
|
||||
go build
|
||||
GO111MODULE=on go build ./cmd/traefik
|
||||
./traefik
|
||||
|
265
README.md
@ -1,155 +1,176 @@
|
||||

|
||||
___
|
||||
|
||||
[](https://circleci.com/gh/emilevauge/traefik)
|
||||
[](https://github.com/EmileVauge/traefik/blob/master/LICENSE.md)
|
||||
[](https://traefik.herokuapp.com)
|
||||
<p align="center">
|
||||
<img src="docs/content/assets/img/traefik.logo.png" alt="Traefik" title="Traefik" />
|
||||
</p>
|
||||
|
||||
[](https://semaphoreci.com/containous/traefik)
|
||||
[](https://docs.traefik.io)
|
||||
[](http://goreportcard.com/report/containous/traefik)
|
||||
[](https://microbadger.com/images/traefik)
|
||||
[](https://github.com/containous/traefik/blob/master/LICENSE.md)
|
||||
[](https://community.containo.us/)
|
||||
[](https://twitter.com/intent/follow?screen_name=traefik)
|
||||
|
||||
|
||||
Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
It supports several backends ([Docker :whale:](https://www.docker.com/), [Mesos/Marathon](https://mesosphere.github.io/marathon/), [Consul](https://consul.io/), [Etcd](https://coreos.com/etcd/), [Zookeeper](https://zookeeper.apache.org), [BoltDB](https://github.com/boltdb/bolt), Rest API, file...) to manage its configuration automatically and dynamically.
|
||||
Traefik (pronounced _traffic_) is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
||||
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
|
||||
Pointing Traefik at your orchestrator should be the _only_ configuration step you need.
|
||||
|
||||
---
|
||||
|
||||
. **[Overview](#overview)** .
|
||||
**[Features](#features)** .
|
||||
**[Supported backends](#supported-backends)** .
|
||||
**[Quickstart](#quickstart)** .
|
||||
**[Web UI](#web-ui)** .
|
||||
**[Documentation](#documentation)** .
|
||||
|
||||
. **[Support](#support)** .
|
||||
**[Release cycle](#release-cycle)** .
|
||||
**[Contributing](#contributing)** .
|
||||
**[Maintainers](#maintainers)** .
|
||||
**[Credits](#credits)** .
|
||||
|
||||
---
|
||||
|
||||
:warning: Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now. If you're testing out v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/v2.0/).
|
||||
|
||||
## Overview
|
||||
|
||||
Imagine that you have deployed a bunch of microservices with the help of an orchestrator (like Swarm or Kubernetes) or a service registry (like etcd or consul).
|
||||
Now you want users to access these microservices, and you need a reverse proxy.
|
||||
|
||||
Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
|
||||
In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
|
||||
|
||||
**This is when Traefik can help you!**
|
||||
|
||||
Traefik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
|
||||
|
||||
**Run Traefik and let it do the work for you!**
|
||||
_(But if you'd rather configure some of your routes manually, Traefik supports that too!)_
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- No dependency hell, single binary made with go
|
||||
- Simple json Rest API
|
||||
- Simple TOML file configuration
|
||||
- Multiple backends supported: Docker, Mesos/Marathon, Consul, Etcd, and more to come
|
||||
- Watchers for backends, can listen change in backends to apply a new configuration automatically
|
||||
- Hot-reloading of configuration. No need to restart the process
|
||||
- Graceful shutdown http connections during hot-reloads
|
||||
- Circuit breakers on backends
|
||||
- Round Robin, rebalancer load-balancers
|
||||
- Rest Metrics
|
||||
- Tiny docker image included
|
||||
- SSL backends support
|
||||
- SSL frontend support
|
||||
- Clean AngularJS Web UI
|
||||
- Websocket support
|
||||
- Continuously updates its configuration (No restarts!)
|
||||
- Supports multiple load balancing algorithms
|
||||
- Provides HTTPS to your microservices by leveraging [Let's Encrypt](https://letsencrypt.org) (wildcard certificates support)
|
||||
- Circuit breakers, retry
|
||||
- See the magic through its clean web UI
|
||||
- Websocket, HTTP/2, GRPC ready
|
||||
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB)
|
||||
- Keeps access logs (JSON, CLF)
|
||||
- Fast
|
||||
- Exposes a Rest API
|
||||
- Packaged as a single binary file (made with :heart: with go) and available as a [tiny](https://microbadger.com/images/traefik) [official](https://hub.docker.com/r/_/traefik/) docker image
|
||||
|
||||
## Demo
|
||||
|
||||
Here is a demo of Træfɪk using Docker backend, showing a load-balancing between two servers, hot reloading of configuration, and graceful shutdown.
|
||||
## Supported Backends
|
||||
|
||||
[](https://asciinema.org/a/4tcyde7riou5vxulo6my3mtko)
|
||||
- [Docker](https://docs.traefik.io/configuration/backends/docker) / [Swarm mode](https://docs.traefik.io/configuration/backends/docker#docker-swarm-mode)
|
||||
- [Kubernetes](https://docs.traefik.io/configuration/backends/kubernetes)
|
||||
- [Mesos](https://docs.traefik.io/configuration/backends/mesos) / [Marathon](https://docs.traefik.io/configuration/backends/marathon)
|
||||
- [Rancher](https://docs.traefik.io/configuration/backends/rancher) (API, Metadata)
|
||||
- [Azure Service Fabric](https://docs.traefik.io/configuration/backends/servicefabric)
|
||||
- [Consul Catalog](https://docs.traefik.io/configuration/backends/consulcatalog)
|
||||
- [Consul](https://docs.traefik.io/configuration/backends/consul) / [Etcd](https://docs.traefik.io/configuration/backends/etcd) / [Zookeeper](https://docs.traefik.io/configuration/backends/zookeeper) / [BoltDB](https://docs.traefik.io/configuration/backends/boltdb)
|
||||
- [Eureka](https://docs.traefik.io/configuration/backends/eureka)
|
||||
- [Amazon ECS](https://docs.traefik.io/configuration/backends/ecs)
|
||||
- [Amazon DynamoDB](https://docs.traefik.io/configuration/backends/dynamodb)
|
||||
- [File](https://docs.traefik.io/configuration/backends/file)
|
||||
- [Rest](https://docs.traefik.io/configuration/backends/rest)
|
||||
|
||||
## Quickstart
|
||||
|
||||
To get your hands on Traefik, you can use the [5-Minute Quickstart](http://docs.traefik.io/#the-traefik-quickstart-using-docker) in our documentation (you will need Docker).
|
||||
|
||||
## Web UI
|
||||
|
||||
You can access to a simple HTML frontend of Træfik.
|
||||
You can access the simple HTML frontend of Traefik.
|
||||
|
||||

|
||||

|
||||
|
||||
## Plumbing
|
||||
|
||||
- [Oxy](https://github.com/mailgun/oxy/): an awsome proxy library made by Mailgun guys
|
||||
- [Gorilla mux](https://github.com/gorilla/mux): famous request router
|
||||
- [Negroni](https://github.com/codegangsta/negroni): web middlewares made simple
|
||||
- [Manners](https://github.com/mailgun/manners): graceful shutdown of http.Handler servers
|
||||
|
||||
## Quick start
|
||||
|
||||
- The simple way: grab the latest binary from the [releases](https://github.com/emilevauge/traefik/releases) page and just run it with the [sample configuration file](https://raw.githubusercontent.com/EmileVauge/traefik/master/traefik.sample.toml):
|
||||
|
||||
```shell
|
||||
./traefik traefik.toml
|
||||
```
|
||||
|
||||
- Use the tiny Docker image:
|
||||
|
||||
```shell
|
||||
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/traefik.toml emilevauge/traefik
|
||||
```
|
||||
|
||||
- From sources:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/EmileVauge/traefik
|
||||
```
|
||||

|
||||
|
||||
## Documentation
|
||||
|
||||
You can find the complete documentation [here](docs/index.md).
|
||||
You can find the complete documentation at [https://docs.traefik.io](https://docs.traefik.io).
|
||||
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
||||
|
||||
## Benchmarks
|
||||
:warning: If you're testing out v2, please ensure you are using the [v2 documentation](https://docs.traefik.io/v2.0/).
|
||||
|
||||
Refer to the [benchmarks section](docs/index.md#benchmarks) in the documentation.
|
||||
## Support
|
||||
|
||||
To get community support, you can:
|
||||
- join the Traefik community forum: [](https://community.containo.us/)
|
||||
|
||||
If you need commercial support, please contact [Containo.us](https://containo.us) by mail: <mailto:support@containo.us>.
|
||||
|
||||
## Download
|
||||
|
||||
- Grab the latest binary from the [releases](https://github.com/containous/traefik/releases) page and run it with the [sample configuration file](https://raw.githubusercontent.com/containous/traefik/master/traefik.sample.toml):
|
||||
|
||||
```shell
|
||||
./traefik --configFile=traefik.toml
|
||||
```
|
||||
|
||||
- Or use the official tiny Docker image and run it with the [sample configuration file](https://raw.githubusercontent.com/containous/traefik/master/traefik.sample.toml):
|
||||
|
||||
```shell
|
||||
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik
|
||||
```
|
||||
|
||||
- Or get the sources:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/containous/traefik
|
||||
```
|
||||
|
||||
## Introductory Videos
|
||||
|
||||
:warning: Please be aware that these videos are for v1.X. The old configurations for Traefik v1.X are NOT compatible with Traefik v2. If you're testing out v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/v2.0/).
|
||||
|
||||
Here is a talk given by [Emile Vauge](https://github.com/emilevauge) at GopherCon 2017.
|
||||
You will learn Traefik basics in less than 10 minutes.
|
||||
|
||||
[](https://www.youtube.com/watch?v=RgudiksfL-k)
|
||||
|
||||
Here is a talk given by [Ed Robinson](https://github.com/errm) at [ContainerCamp UK](https://container.camp) conference.
|
||||
You will learn fundamental Traefik features and see some demos with Kubernetes.
|
||||
|
||||
[](https://www.youtube.com/watch?v=aFtpIShV60I)
|
||||
|
||||
## Maintainers
|
||||
|
||||
[Information about process and maintainers](docs/content/contributing/maintainers.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
### Building
|
||||
If you'd like to contribute to the project, refer to the [contributing documentation](CONTRIBUTING.md).
|
||||
|
||||
You need either [Docker](https://github.com/docker/docker) and `make`, or `go` and `glide` in order to build traefik.
|
||||
Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
By participating in this project, you agree to abide by its terms.
|
||||
|
||||
#### Setting up your `go` environment
|
||||
- You need `go` v1.5
|
||||
- You need to set `export GO15VENDOREXPERIMENT=1` environment variable
|
||||
- If you clone Træfɪk into something like `~/go/src/github.com/traefik`, your `GOPATH` variable will have to be set to `~/go`: export `GOPATH=~/go`.
|
||||
## Release Cycle
|
||||
|
||||
#### Using `Docker` and `Makefile`
|
||||
- We release a new version (e.g. 1.1.0, 1.2.0, 1.3.0) every other month.
|
||||
- Release Candidates are available before the release (e.g. 1.1.0-rc1, 1.1.0-rc2, 1.1.0-rc3, 1.1.0-rc4, before 1.1.0)
|
||||
- Bug-fixes (e.g. 1.1.1, 1.1.2, 1.2.1, 1.2.3) are released as needed (no additional features are delivered in those versions, bug-fixes only)
|
||||
|
||||
You need to run the `binary` target. This will create binaries for
|
||||
linux platform in the `dist` folder.
|
||||
Each version is supported until the next one is released (e.g. 1.1.x will be supported until 1.2.0 is out)
|
||||
|
||||
```bash
|
||||
$ make binary
|
||||
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.5
|
||||
---> 8c6473912976
|
||||
Step 1 : RUN go get github.com/Masterminds/glide
|
||||
[...]
|
||||
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/emile/dev/go/src/github.com/emilevauge/traefik/"dist":/go/src/github.com/emilevauge/traefik/"dist"" "traefik-dev:no-more-godep-ever" ./script/make.sh generate binary
|
||||
---> Making bundle: generate (in .)
|
||||
removed 'gen.go'
|
||||
We use [Semantic Versioning](http://semver.org/)
|
||||
|
||||
---> Making bundle: binary (in .)
|
||||
## Mailing lists
|
||||
|
||||
$ ls dist/
|
||||
traefik*
|
||||
```
|
||||
- General announcements, new releases: mail at news+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/news)
|
||||
- Security announcements: mail at security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
|
||||
#### Using `glide`
|
||||
## Credits
|
||||
|
||||
The idea behind `glide` is the following :
|
||||
Kudos to [Peka](http://peka.byethost11.com/photoblog/) for his awesome work on the logo .
|
||||
|
||||
- when checkout(ing) a project, **run `glide up`** to install
|
||||
(`go get …`) the dependencies in the `GOPATH`.
|
||||
- if you need another dependency, import and use it in
|
||||
the source, and **run `glide get github.com/Masterminds/cookoo`** to save it in
|
||||
`vendor` and add it to your `glide.yaml`.
|
||||
Traefik's logo is licensed under the Creative Commons 3.0 Attributions license.
|
||||
|
||||
```bash
|
||||
$ glide up --update-vendored
|
||||
# generate
|
||||
$ go generate
|
||||
# Simple go build
|
||||
$ go build
|
||||
# Using gox to build multiple platform
|
||||
$ gox "linux darwin" "386 amd64 arm" \
|
||||
-output="dist/traefik_{{.OS}}-{{.Arch}}"
|
||||
# run other commands like tests
|
||||
$ go test ./...
|
||||
ok _/home/vincent/src/github/vdemeester/traefik 0.004s
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
You can run unit tests using the `test-unit` target and the
|
||||
integration test using the `test-integration` target.
|
||||
|
||||
```bash
|
||||
$ make test-unit
|
||||
docker build -t "traefik-dev:your-feature-branch" -f build.Dockerfile .
|
||||
# […]
|
||||
docker run --rm -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -v "/home/vincent/src/github/vdemeester/traefik/dist:/go/src/github.com/emilevauge/traefik/dist" "traefik-dev:your-feature-branch" ./script/make.sh generate test-unit
|
||||
---> Making bundle: generate (in .)
|
||||
removed 'gen.go'
|
||||
|
||||
---> Making bundle: test-unit (in .)
|
||||
+ go test -cover -coverprofile=cover.out .
|
||||
ok github.com/emilevauge/traefik 0.005s coverage: 4.1% of statements
|
||||
|
||||
Test success
|
||||
```
|
||||
Traefik's logo was inspired by the gopher stickers made by Takuya Ueda (https://twitter.com/tenntenn).
|
||||
The original Go gopher was designed by Renee French (http://reneefrench.blogspot.com/).
|
||||
|
45
adapters.go
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mailgun/oxy/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type OxyLogger struct {
|
||||
}
|
||||
|
||||
func (oxylogger *OxyLogger) Infof(format string, args ...interface{}) {
|
||||
log.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (oxylogger *OxyLogger) Warningf(format string, args ...interface{}) {
|
||||
log.Warningf(format, args...)
|
||||
}
|
||||
|
||||
func (oxylogger *OxyLogger) Errorf(format string, args ...interface{}) {
|
||||
log.Errorf(format, args...)
|
||||
}
|
||||
|
||||
type ErrorHandler struct {
|
||||
}
|
||||
|
||||
func (e *ErrorHandler) ServeHTTP(w http.ResponseWriter, req *http.Request, err error) {
|
||||
log.Error("server error ", err.Error())
|
||||
utils.DefaultHandler.ServeHTTP(w, req, err)
|
||||
}
|
||||
|
||||
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
//templatesRenderer.HTML(w, http.StatusNotFound, "notFound", nil)
|
||||
}
|
||||
|
||||
func LoadDefaultConfig(globalConfiguration *GlobalConfiguration) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
|
||||
return router
|
||||
}
|
14
boltdb.go
@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
type BoltDbProvider struct {
|
||||
Watch bool
|
||||
Endpoint string
|
||||
Prefix string
|
||||
Filename string
|
||||
KvProvider *KvProvider
|
||||
}
|
||||
|
||||
func (provider *BoltDbProvider) Provide(configurationChan chan<- configMessage) error {
|
||||
provider.KvProvider = NewBoltDbProvider(provider)
|
||||
return provider.KvProvider.provide(configurationChan)
|
||||
}
|
@ -1,26 +1,37 @@
|
||||
FROM golang:1.5
|
||||
FROM golang:1.13-alpine
|
||||
|
||||
RUN go get github.com/Masterminds/glide
|
||||
RUN go get github.com/mitchellh/gox
|
||||
RUN go get github.com/tcnksm/ghr
|
||||
RUN apk --update upgrade \
|
||||
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
|
||||
&& update-ca-certificates \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Which docker version to test on
|
||||
ENV DOCKER_VERSION 1.6.2
|
||||
|
||||
# enable GO15VENDOREXPERIMENT
|
||||
ENV GO15VENDOREXPERIMENT 1
|
||||
ARG DOCKER_VERSION=18.09.7
|
||||
|
||||
# Download docker
|
||||
RUN set -ex; \
|
||||
curl https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION} -o /usr/local/bin/docker-${DOCKER_VERSION}; \
|
||||
chmod +x /usr/local/bin/docker-${DOCKER_VERSION}
|
||||
RUN mkdir -p /usr/local/bin \
|
||||
&& curl -fL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
|
||||
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
||||
|
||||
# Set the default Docker to be run
|
||||
RUN ln -s /usr/local/bin/docker-${DOCKER_VERSION} /usr/local/bin/docker
|
||||
# Download go-bindata binary to bin folder in $GOPATH
|
||||
RUN mkdir -p /usr/local/bin \
|
||||
&& curl -fsSL -o /usr/local/bin/go-bindata https://github.com/containous/go-bindata/releases/download/v1.0.0/go-bindata \
|
||||
&& chmod +x /usr/local/bin/go-bindata
|
||||
|
||||
WORKDIR /go/src/github.com/emilevauge/traefik
|
||||
# Download golangci-lint binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.18.0
|
||||
|
||||
COPY glide.yaml glide.yaml
|
||||
RUN glide up
|
||||
# Download golangci-lint and misspell binary to bin folder in $GOPATH
|
||||
RUN GO111MODULE=off go get github.com/client9/misspell/cmd/misspell
|
||||
|
||||
COPY . /go/src/github.com/emilevauge/traefik
|
||||
# Download goreleaser binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh
|
||||
|
||||
WORKDIR /go/src/github.com/containous/traefik
|
||||
|
||||
# Download go modules
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download
|
||||
|
||||
COPY . /go/src/github.com/containous/traefik
|
||||
|
36
circle.yml
@ -1,36 +0,0 @@
|
||||
machine:
|
||||
pre:
|
||||
- sudo docker -d -e lxc -s btrfs -H tcp://0.0.0.0:2375:
|
||||
background: true
|
||||
- curl --retry 15 --retry-delay 3 -v http://172.17.42.1:2375/version
|
||||
environment:
|
||||
REPO: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
|
||||
DOCKER_HOST: tcp://172.17.42.1:2375
|
||||
MAKE_DOCKER_HOST: $DOCKER_HOST
|
||||
VERSION: v1.0.alpha.$CIRCLE_BUILD_NUM
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- docker version
|
||||
- go get github.com/tcnksm/ghr
|
||||
- make validate
|
||||
override:
|
||||
- make binary
|
||||
|
||||
test:
|
||||
override:
|
||||
- make test-unit
|
||||
- make test-integration
|
||||
post:
|
||||
- make crossbinary
|
||||
- make image
|
||||
|
||||
deployment:
|
||||
hub:
|
||||
branch: master
|
||||
commands:
|
||||
- ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME --prerelease ${VERSION} dist/
|
||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- docker push ${REPO,,}:latest
|
||||
- docker tag ${REPO,,}:latest ${REPO,,}:${VERSION}
|
||||
- docker push ${REPO,,}:${VERSION}
|
34
cmd/configuration.go
Normal file
@ -0,0 +1,34 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/static"
|
||||
"github.com/containous/traefik/v2/pkg/types"
|
||||
)
|
||||
|
||||
// TraefikCmdConfiguration wraps the static configuration and extra parameters.
|
||||
type TraefikCmdConfiguration struct {
|
||||
static.Configuration `export:"true"`
|
||||
// ConfigFile is the path to the configuration file.
|
||||
ConfigFile string `description:"Configuration file to use. If specified all other flags are ignored." export:"true"`
|
||||
}
|
||||
|
||||
// NewTraefikConfiguration creates a TraefikCmdConfiguration with default values.
|
||||
func NewTraefikConfiguration() *TraefikCmdConfiguration {
|
||||
return &TraefikCmdConfiguration{
|
||||
Configuration: static.Configuration{
|
||||
Global: &static.Global{
|
||||
CheckNewVersion: true,
|
||||
},
|
||||
EntryPoints: make(static.EntryPoints),
|
||||
Providers: &static.Providers{
|
||||
ProvidersThrottleDuration: types.Duration(2 * time.Second),
|
||||
},
|
||||
ServersTransport: &static.ServersTransport{
|
||||
MaxIdleConnsPerHost: 200,
|
||||
},
|
||||
},
|
||||
ConfigFile: "",
|
||||
}
|
||||
}
|
22
cmd/context.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ContextWithSignal creates a context canceled when SIGINT or SIGTERM are notified
|
||||
func ContextWithSignal(ctx context.Context) context.Context {
|
||||
newCtx, cancel := context.WithCancel(ctx)
|
||||
signals := make(chan os.Signal)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
select {
|
||||
case <-signals:
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
return newCtx
|
||||
}
|
74
cmd/healthcheck/healthcheck.go
Normal file
@ -0,0 +1,74 @@
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/cli"
|
||||
"github.com/containous/traefik/v2/pkg/config/static"
|
||||
)
|
||||
|
||||
// NewCmd builds a new HealthCheck command.
|
||||
func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLoader) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "healthcheck",
|
||||
Description: `Calls Traefik /ping to check the health of Traefik (the API must be enabled).`,
|
||||
Configuration: traefikConfiguration,
|
||||
Run: runCmd(traefikConfiguration),
|
||||
Resources: loaders,
|
||||
}
|
||||
}
|
||||
|
||||
func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
|
||||
return func(_ []string) error {
|
||||
traefikConfiguration.SetEffectiveConfiguration()
|
||||
|
||||
resp, errPing := Do(*traefikConfiguration)
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if errPing != nil {
|
||||
fmt.Printf("Error calling healthcheck: %s\n", errPing)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
fmt.Printf("Bad healthcheck status: %s\n", resp.Status)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("OK: %s\n", resp.Request.URL)
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Do try to do a healthcheck
|
||||
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
|
||||
if staticConfiguration.Ping == nil {
|
||||
return nil, errors.New("please enable `ping` to use health check")
|
||||
}
|
||||
|
||||
pingEntryPoint, ok := staticConfiguration.EntryPoints["traefik"]
|
||||
if !ok {
|
||||
return nil, errors.New("missing `ping` entrypoint")
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
protocol := "http"
|
||||
|
||||
// FIXME Handle TLS on ping etc...
|
||||
// if pingEntryPoint.TLS != nil {
|
||||
// protocol = "https"
|
||||
// tr := &http.Transport{
|
||||
// TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
// }
|
||||
// client.Transport = tr
|
||||
// }
|
||||
|
||||
path := "/"
|
||||
|
||||
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
|
||||
}
|
315
cmd/traefik/traefik.go
Normal file
@ -0,0 +1,315 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
stdlog "log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/v2/autogen/genstatic"
|
||||
"github.com/containous/traefik/v2/cmd"
|
||||
"github.com/containous/traefik/v2/cmd/healthcheck"
|
||||
cmdVersion "github.com/containous/traefik/v2/cmd/version"
|
||||
"github.com/containous/traefik/v2/pkg/cli"
|
||||
"github.com/containous/traefik/v2/pkg/collector"
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/config/static"
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
"github.com/containous/traefik/v2/pkg/provider/acme"
|
||||
"github.com/containous/traefik/v2/pkg/provider/aggregator"
|
||||
"github.com/containous/traefik/v2/pkg/safe"
|
||||
"github.com/containous/traefik/v2/pkg/server"
|
||||
"github.com/containous/traefik/v2/pkg/server/router"
|
||||
traefiktls "github.com/containous/traefik/v2/pkg/tls"
|
||||
"github.com/containous/traefik/v2/pkg/version"
|
||||
"github.com/coreos/go-systemd/daemon"
|
||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vulcand/oxy/roundrobin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// traefik config inits
|
||||
tConfig := cmd.NewTraefikConfiguration()
|
||||
|
||||
loaders := []cli.ResourceLoader{&cli.FileLoader{}, &cli.FlagLoader{}, &cli.EnvLoader{}}
|
||||
|
||||
cmdTraefik := &cli.Command{
|
||||
Name: "traefik",
|
||||
Description: `Traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||
Complete documentation is available at https://traefik.io`,
|
||||
Configuration: tConfig,
|
||||
Resources: loaders,
|
||||
Run: func(_ []string) error {
|
||||
return runCmd(&tConfig.Configuration)
|
||||
},
|
||||
}
|
||||
|
||||
err := cmdTraefik.AddCommand(healthcheck.NewCmd(&tConfig.Configuration, loaders))
|
||||
if err != nil {
|
||||
stdlog.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = cmdTraefik.AddCommand(cmdVersion.NewCmd())
|
||||
if err != nil {
|
||||
stdlog.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = cli.Execute(cmdTraefik)
|
||||
if err != nil {
|
||||
stdlog.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func runCmd(staticConfiguration *static.Configuration) error {
|
||||
configureLogging(staticConfiguration)
|
||||
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
if err := roundrobin.SetDefaultWeight(0); err != nil {
|
||||
log.WithoutContext().Errorf("Could not set roundrobin default weight: %v", err)
|
||||
}
|
||||
|
||||
staticConfiguration.SetEffectiveConfiguration()
|
||||
if err := staticConfiguration.ValidateConfiguration(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.WithoutContext().Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
|
||||
|
||||
jsonConf, err := json.Marshal(staticConfiguration)
|
||||
if err != nil {
|
||||
log.WithoutContext().Errorf("Could not marshal static configuration: %v", err)
|
||||
log.WithoutContext().Debugf("Static configuration loaded [struct] %#v", staticConfiguration)
|
||||
} else {
|
||||
log.WithoutContext().Debugf("Static configuration loaded %s", string(jsonConf))
|
||||
}
|
||||
|
||||
if staticConfiguration.API != nil && staticConfiguration.API.Dashboard {
|
||||
staticConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
|
||||
}
|
||||
|
||||
if staticConfiguration.Global.CheckNewVersion {
|
||||
checkNewVersion()
|
||||
}
|
||||
|
||||
stats(staticConfiguration)
|
||||
|
||||
providerAggregator := aggregator.NewProviderAggregator(*staticConfiguration.Providers)
|
||||
|
||||
tlsManager := traefiktls.NewManager()
|
||||
|
||||
acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager)
|
||||
|
||||
serverEntryPointsTCP := make(server.TCPEntryPoints)
|
||||
for entryPointName, config := range staticConfiguration.EntryPoints {
|
||||
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
|
||||
serverEntryPointsTCP[entryPointName], err = server.NewTCPEntryPoint(ctx, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while building entryPoint %s: %v", entryPointName, err)
|
||||
}
|
||||
serverEntryPointsTCP[entryPointName].RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProviders)
|
||||
|
||||
}
|
||||
|
||||
svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPointsTCP, tlsManager)
|
||||
|
||||
resolverNames := map[string]struct{}{}
|
||||
|
||||
for _, p := range acmeProviders {
|
||||
resolverNames[p.ResolverName] = struct{}{}
|
||||
svr.AddListener(p.ListenConfiguration)
|
||||
}
|
||||
|
||||
svr.AddListener(func(config dynamic.Configuration) {
|
||||
for rtName, rt := range config.HTTP.Routers {
|
||||
if rt.TLS == nil || rt.TLS.CertResolver == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := resolverNames[rt.TLS.CertResolver]; !ok {
|
||||
log.WithoutContext().Errorf("the router %s uses a non-existent resolver: %s", rtName, rt.TLS.CertResolver)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
ctx := cmd.ContextWithSignal(context.Background())
|
||||
|
||||
if staticConfiguration.Ping != nil {
|
||||
staticConfiguration.Ping.WithContext(ctx)
|
||||
}
|
||||
|
||||
svr.Start(ctx)
|
||||
defer svr.Close()
|
||||
|
||||
sent, err := daemon.SdNotify(false, "READY=1")
|
||||
if !sent && err != nil {
|
||||
log.WithoutContext().Errorf("Failed to notify: %v", err)
|
||||
}
|
||||
|
||||
t, err := daemon.SdWatchdogEnabled(false)
|
||||
if err != nil {
|
||||
log.WithoutContext().Errorf("Could not enable Watchdog: %v", err)
|
||||
} else if t != 0 {
|
||||
// Send a ping each half time given
|
||||
t /= 2
|
||||
log.WithoutContext().Infof("Watchdog activated with timer duration %s", t)
|
||||
safe.Go(func() {
|
||||
tick := time.Tick(t)
|
||||
for range tick {
|
||||
resp, errHealthCheck := healthcheck.Do(*staticConfiguration)
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
if staticConfiguration.Ping == nil || errHealthCheck == nil {
|
||||
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
|
||||
log.WithoutContext().Error("Fail to tick watchdog")
|
||||
}
|
||||
} else {
|
||||
log.WithoutContext().Error(errHealthCheck)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
svr.Wait()
|
||||
log.WithoutContext().Info("Shutting down")
|
||||
logrus.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// initACMEProvider creates an acme provider from the ACME part of globalConfiguration
|
||||
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager) []*acme.Provider {
|
||||
challengeStore := acme.NewLocalChallengeStore()
|
||||
localStores := map[string]*acme.LocalStore{}
|
||||
|
||||
var resolvers []*acme.Provider
|
||||
for name, resolver := range c.CertificatesResolvers {
|
||||
if resolver.ACME != nil {
|
||||
if localStores[resolver.ACME.Storage] == nil {
|
||||
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage)
|
||||
}
|
||||
|
||||
p := &acme.Provider{
|
||||
Configuration: resolver.ACME,
|
||||
Store: localStores[resolver.ACME.Storage],
|
||||
ChallengeStore: challengeStore,
|
||||
ResolverName: name,
|
||||
}
|
||||
|
||||
if err := providerAggregator.AddProvider(p); err != nil {
|
||||
log.WithoutContext().Errorf("Unable to add ACME provider to the providers list: %v", err)
|
||||
continue
|
||||
}
|
||||
p.SetTLSManager(tlsManager)
|
||||
if p.TLSChallenge != nil {
|
||||
tlsManager.TLSAlpnGetter = p.GetTLSALPNCertificate
|
||||
}
|
||||
p.SetConfigListenerChan(make(chan dynamic.Configuration))
|
||||
resolvers = append(resolvers, p)
|
||||
}
|
||||
}
|
||||
return resolvers
|
||||
}
|
||||
|
||||
func configureLogging(staticConfiguration *static.Configuration) {
|
||||
// configure default log flags
|
||||
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
|
||||
|
||||
// configure log level
|
||||
// an explicitly defined log level always has precedence. if none is
|
||||
// given and debug mode is disabled, the default is ERROR, and DEBUG
|
||||
// otherwise.
|
||||
levelStr := "error"
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.Level != "" {
|
||||
levelStr = strings.ToLower(staticConfiguration.Log.Level)
|
||||
}
|
||||
|
||||
level, err := logrus.ParseLevel(levelStr)
|
||||
if err != nil {
|
||||
log.WithoutContext().Errorf("Error getting level: %v", err)
|
||||
}
|
||||
log.SetLevel(level)
|
||||
|
||||
var logFile string
|
||||
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
||||
logFile = staticConfiguration.Log.FilePath
|
||||
}
|
||||
|
||||
// configure log format
|
||||
var formatter logrus.Formatter
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.Format == "json" {
|
||||
formatter = &logrus.JSONFormatter{}
|
||||
} else {
|
||||
disableColors := len(logFile) > 0
|
||||
formatter = &logrus.TextFormatter{DisableColors: disableColors, FullTimestamp: true, DisableSorting: true}
|
||||
}
|
||||
log.SetFormatter(formatter)
|
||||
|
||||
if len(logFile) > 0 {
|
||||
dir := filepath.Dir(logFile)
|
||||
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
log.WithoutContext().Errorf("Failed to create log path %s: %s", dir, err)
|
||||
}
|
||||
|
||||
err = log.OpenFile(logFile)
|
||||
logrus.RegisterExitHandler(func() {
|
||||
if err := log.CloseFile(); err != nil {
|
||||
log.WithoutContext().Errorf("Error while closing log: %v", err)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
log.WithoutContext().Errorf("Error while opening log file %s: %v", logFile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkNewVersion() {
|
||||
ticker := time.Tick(24 * time.Hour)
|
||||
safe.Go(func() {
|
||||
for time.Sleep(10 * time.Minute); ; <-ticker {
|
||||
version.CheckNewVersion()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func stats(staticConfiguration *static.Configuration) {
|
||||
logger := log.WithoutContext()
|
||||
|
||||
if staticConfiguration.Global.SendAnonymousUsage {
|
||||
logger.Info(`Stats collection is enabled.`)
|
||||
logger.Info(`Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.`)
|
||||
logger.Info(`Help us improve Traefik by leaving this feature on :)`)
|
||||
logger.Info(`More details on: https://docs.traefik.io/v2.0/contributing/data-collection/`)
|
||||
collect(staticConfiguration)
|
||||
} else {
|
||||
logger.Info(`
|
||||
Stats collection is disabled.
|
||||
Help us improve Traefik by turning this feature on :)
|
||||
More details on: https://docs.traefik.io/v2.0/contributing/data-collection/
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
func collect(staticConfiguration *static.Configuration) {
|
||||
ticker := time.Tick(24 * time.Hour)
|
||||
safe.Go(func() {
|
||||
for time.Sleep(10 * time.Minute); ; <-ticker {
|
||||
if err := collector.Collect(staticConfiguration); err != nil {
|
||||
log.WithoutContext().Debug(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
60
cmd/version/version.go
Normal file
@ -0,0 +1,60 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"text/template"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/cli"
|
||||
"github.com/containous/traefik/v2/pkg/version"
|
||||
)
|
||||
|
||||
var versionTemplate = `Version: {{.Version}}
|
||||
Codename: {{.Codename}}
|
||||
Go version: {{.GoVersion}}
|
||||
Built: {{.BuildTime}}
|
||||
OS/Arch: {{.Os}}/{{.Arch}}`
|
||||
|
||||
// NewCmd builds a new Version command
|
||||
func NewCmd() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "version",
|
||||
Description: `Shows the current Traefik version.`,
|
||||
Configuration: nil,
|
||||
Run: func(_ []string) error {
|
||||
if err := GetPrint(os.Stdout); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Print("\n")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetPrint write Printable version
|
||||
func GetPrint(wr io.Writer) error {
|
||||
tmpl, err := template.New("").Parse(versionTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := struct {
|
||||
Version string
|
||||
Codename string
|
||||
GoVersion string
|
||||
BuildTime string
|
||||
Os string
|
||||
Arch string
|
||||
}{
|
||||
Version: version.Version,
|
||||
Codename: version.Codename,
|
||||
GoVersion: runtime.Version(),
|
||||
BuildTime: version.BuildDate,
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
}
|
||||
|
||||
return tmpl.Execute(wr, v)
|
||||
}
|
113
configuration.go
@ -1,113 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GlobalConfiguration struct {
|
||||
Port string
|
||||
GraceTimeOut int64
|
||||
AccessLogsFile string
|
||||
TraefikLogsFile string
|
||||
CertFile, KeyFile string
|
||||
LogLevel string
|
||||
ProvidersThrottleDuration time.Duration
|
||||
Docker *DockerProvider
|
||||
File *FileProvider
|
||||
Web *WebProvider
|
||||
Marathon *MarathonProvider
|
||||
Consul *ConsulProvider
|
||||
Etcd *EtcdProvider
|
||||
Zookeeper *ZookepperProvider
|
||||
Boltdb *BoltDbProvider
|
||||
}
|
||||
|
||||
func NewGlobalConfiguration() *GlobalConfiguration {
|
||||
globalConfiguration := new(GlobalConfiguration)
|
||||
// default values
|
||||
globalConfiguration.Port = ":80"
|
||||
globalConfiguration.GraceTimeOut = 10
|
||||
globalConfiguration.LogLevel = "ERROR"
|
||||
globalConfiguration.ProvidersThrottleDuration = time.Duration(2 * time.Second)
|
||||
|
||||
return globalConfiguration
|
||||
}
|
||||
|
||||
// Backend configuration
|
||||
type Backend struct {
|
||||
Servers map[string]Server `json:"servers,omitempty"`
|
||||
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty"`
|
||||
LoadBalancer *LoadBalancer `json:"loadBalancer,omitempty"`
|
||||
}
|
||||
|
||||
// LoadBalancer configuration
|
||||
type LoadBalancer struct {
|
||||
Method string `json:"method,omitempty"`
|
||||
}
|
||||
|
||||
// CircuitBreaker configuration
|
||||
type CircuitBreaker struct {
|
||||
Expression string `json:"expression,omitempty"`
|
||||
}
|
||||
|
||||
// Server configuration
|
||||
type Server struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
Weight int `json:"weight,omitempty"`
|
||||
}
|
||||
|
||||
// Route configuration
|
||||
type Route struct {
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// Frontend configuration
|
||||
type Frontend struct {
|
||||
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
||||
Backend string `json:"backend,omitempty"`
|
||||
Routes map[string]Route `json:"routes,omitempty"`
|
||||
}
|
||||
|
||||
// Configuration of a provider
|
||||
type Configuration struct {
|
||||
Backends map[string]*Backend `json:"backends,omitempty"`
|
||||
Frontends map[string]*Frontend `json:"frontends,omitempty"`
|
||||
}
|
||||
|
||||
// Load Balancer Method
|
||||
type LoadBalancerMethod uint8
|
||||
|
||||
const (
|
||||
// wrr (default) = Weighted Round Robin
|
||||
wrr LoadBalancerMethod = iota
|
||||
// drr = Dynamic Round Robin
|
||||
drr
|
||||
)
|
||||
|
||||
var loadBalancerMethodNames = []string{
|
||||
"wrr",
|
||||
"drr",
|
||||
}
|
||||
|
||||
func NewLoadBalancerMethod(loadBalancer *LoadBalancer) (LoadBalancerMethod, error) {
|
||||
if loadBalancer != nil {
|
||||
for i, name := range loadBalancerMethodNames {
|
||||
if strings.EqualFold(name, loadBalancer.Method) {
|
||||
return LoadBalancerMethod(i), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrr, ErrInvalidLoadBalancerMethod
|
||||
}
|
||||
|
||||
var ErrInvalidLoadBalancerMethod = errors.New("Invalid method, using default")
|
||||
|
||||
type configMessage struct {
|
||||
providerName string
|
||||
configuration *Configuration
|
||||
}
|
||||
|
||||
type configs map[string]*Configuration
|
14
consul.go
@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
type ConsulProvider struct {
|
||||
Watch bool
|
||||
Endpoint string
|
||||
Prefix string
|
||||
Filename string
|
||||
KvProvider *KvProvider
|
||||
}
|
||||
|
||||
func (provider *ConsulProvider) Provide(configurationChan chan<- configMessage) error {
|
||||
provider.KvProvider = NewConsulProvider(provider)
|
||||
return provider.KvProvider.provide(configurationChan)
|
||||
}
|
1374
contrib/grafana/traefik-kubernetes.json
Normal file
1055
contrib/grafana/traefik.json
Normal file
41
contrib/systemd/traefik.service
Normal file
@ -0,0 +1,41 @@
|
||||
[Unit]
|
||||
Description=Traefik
|
||||
Documentation=https://docs.traefik.io
|
||||
#After=network-online.target
|
||||
#AssertFileIsExecutable=/usr/bin/traefik
|
||||
#AssertPathExists=/etc/traefik/traefik.toml
|
||||
|
||||
[Service]
|
||||
# Run traefik as its own user (create new user with: useradd -r -s /bin/false -U -M traefik)
|
||||
#User=traefik
|
||||
#AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
# configure service behavior
|
||||
Type=notify
|
||||
#ExecStart=/usr/bin/traefik --configFile=/etc/traefik/traefik.toml
|
||||
Restart=always
|
||||
WatchdogSec=1s
|
||||
|
||||
# lock down system access
|
||||
# prohibit any operating system and configuration modification
|
||||
#ProtectSystem=strict
|
||||
# create separate, new (and empty) /tmp and /var/tmp filesystems
|
||||
#PrivateTmp=true
|
||||
# make /home directories inaccessible
|
||||
#ProtectHome=true
|
||||
# turns off access to physical devices (/dev/...)
|
||||
#PrivateDevices=true
|
||||
# make kernel settings (procfs and sysfs) read-only
|
||||
#ProtectKernelTunables=true
|
||||
# make cgroups /sys/fs/cgroup read-only
|
||||
#ProtectControlGroups=true
|
||||
|
||||
# allow writing of acme.json
|
||||
#ReadWritePaths=/etc/traefik/acme.json
|
||||
# depending on log and entrypoint configuration, you may need to allow writing to other paths, too
|
||||
|
||||
# limit number of processes in this unit
|
||||
#LimitNPROC=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
245
docker.go
@ -1,245 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/BurntSushi/ty/fun"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
type DockerProvider struct {
|
||||
Watch bool
|
||||
Endpoint string
|
||||
Filename string
|
||||
Domain string
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) Provide(configurationChan chan<- configMessage) error {
|
||||
if dockerClient, err := docker.NewClient(provider.Endpoint); err != nil {
|
||||
log.Errorf("Failed to create a client for docker, error: %s", err)
|
||||
return err
|
||||
} else {
|
||||
err := dockerClient.Ping()
|
||||
if err != nil {
|
||||
log.Errorf("Docker connection error %+v", err)
|
||||
return err
|
||||
}
|
||||
log.Debug("Docker connection established")
|
||||
if provider.Watch {
|
||||
dockerEvents := make(chan *docker.APIEvents)
|
||||
dockerClient.AddEventListener(dockerEvents)
|
||||
log.Debug("Docker listening")
|
||||
go func() {
|
||||
operation := func() error {
|
||||
for {
|
||||
event := <-dockerEvents
|
||||
if event == nil {
|
||||
return errors.New("Docker event nil")
|
||||
// log.Fatalf("Docker connection error")
|
||||
}
|
||||
if event.Status == "start" || event.Status == "die" {
|
||||
log.Debugf("Docker event receveived %+v", event)
|
||||
configuration := provider.loadDockerConfig(dockerClient)
|
||||
if configuration != nil {
|
||||
configurationChan <- configMessage{"docker", configuration}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
notify := func(err error, time time.Duration) {
|
||||
log.Errorf("Docker connection error %+v, retrying in %s", err, time)
|
||||
}
|
||||
err := backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify)
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot connect to docker server %+v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
configuration := provider.loadDockerConfig(dockerClient)
|
||||
configurationChan <- configMessage{"docker", configuration}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) loadDockerConfig(dockerClient *docker.Client) *Configuration {
|
||||
var DockerFuncMap = template.FuncMap{
|
||||
"getBackend": func(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.backend"); err == nil {
|
||||
return label
|
||||
}
|
||||
return provider.getEscapedName(container.Name)
|
||||
},
|
||||
"getPort": func(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.port"); err == nil {
|
||||
return label
|
||||
}
|
||||
for key := range container.NetworkSettings.Ports {
|
||||
return key.Port()
|
||||
}
|
||||
return ""
|
||||
},
|
||||
"getWeight": func(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.weight"); err == nil {
|
||||
return label
|
||||
}
|
||||
return "0"
|
||||
},
|
||||
"getDomain": func(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.domain"); err == nil {
|
||||
return label
|
||||
}
|
||||
return provider.Domain
|
||||
},
|
||||
"getProtocol": func(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.protocol"); err == nil {
|
||||
return label
|
||||
}
|
||||
return "http"
|
||||
},
|
||||
"getPassHostHeader": func(container docker.Container) string {
|
||||
if passHostHeader, err := provider.getLabel(container, "traefik.frontend.passHostHeader"); err == nil {
|
||||
return passHostHeader
|
||||
}
|
||||
return "false"
|
||||
},
|
||||
"getFrontendValue": provider.GetFrontendValue,
|
||||
"getFrontendRule": provider.GetFrontendRule,
|
||||
"replace": func(s1 string, s2 string, s3 string) string {
|
||||
return strings.Replace(s3, s1, s2, -1)
|
||||
},
|
||||
}
|
||||
configuration := new(Configuration)
|
||||
containerList, _ := dockerClient.ListContainers(docker.ListContainersOptions{})
|
||||
containersInspected := []docker.Container{}
|
||||
frontends := map[string][]docker.Container{}
|
||||
|
||||
// get inspect containers
|
||||
for _, container := range containerList {
|
||||
containerInspected, _ := dockerClient.InspectContainer(container.ID)
|
||||
containersInspected = append(containersInspected, *containerInspected)
|
||||
}
|
||||
|
||||
// filter containers
|
||||
filteredContainers := fun.Filter(func(container docker.Container) bool {
|
||||
if len(container.NetworkSettings.Ports) == 0 {
|
||||
log.Debugf("Filtering container without port %s", container.Name)
|
||||
return false
|
||||
}
|
||||
_, err := strconv.Atoi(container.Config.Labels["traefik.port"])
|
||||
if len(container.NetworkSettings.Ports) > 1 && err != nil {
|
||||
log.Debugf("Filtering container with more than 1 port and no traefik.port label %s", container.Name)
|
||||
return false
|
||||
}
|
||||
if container.Config.Labels["traefik.enable"] == "false" {
|
||||
log.Debugf("Filtering disabled container %s", container.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
if _, err := provider.getLabels(container, []string{"traefik.frontend.rule", "traefik.frontend.value"}); err != nil {
|
||||
log.Debugf("Filtering bad labeled container %s", container.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, containersInspected).([]docker.Container)
|
||||
|
||||
for _, container := range filteredContainers {
|
||||
frontends[provider.getFrontendName(container)] = append(frontends[provider.getFrontendName(container)], container)
|
||||
}
|
||||
|
||||
templateObjects := struct {
|
||||
Containers []docker.Container
|
||||
Frontends map[string][]docker.Container
|
||||
Domain string
|
||||
}{
|
||||
filteredContainers,
|
||||
frontends,
|
||||
provider.Domain,
|
||||
}
|
||||
tmpl := template.New(provider.Filename).Funcs(DockerFuncMap)
|
||||
if len(provider.Filename) > 0 {
|
||||
_, err := tmpl.ParseFiles(provider.Filename)
|
||||
if err != nil {
|
||||
log.Error("Error reading file", err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
buf, err := Asset("templates/docker.tmpl")
|
||||
if err != nil {
|
||||
log.Error("Error reading file", err)
|
||||
}
|
||||
_, err = tmpl.Parse(string(buf))
|
||||
if err != nil {
|
||||
log.Error("Error reading file", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err := tmpl.Execute(&buffer, templateObjects)
|
||||
if err != nil {
|
||||
log.Error("Error with docker template", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := toml.Decode(buffer.String(), configuration); err != nil {
|
||||
log.Error("Error creating docker configuration ", err)
|
||||
return nil
|
||||
}
|
||||
return configuration
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) getFrontendName(container docker.Container) string {
|
||||
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
||||
frontendName := fmt.Sprintf("%s-%s", provider.GetFrontendRule(container), provider.GetFrontendValue(container))
|
||||
return strings.Replace(frontendName, ".", "-", -1)
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) getEscapedName(name string) string {
|
||||
return strings.Replace(name, "/", "", -1)
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) getLabel(container docker.Container, label string) (string, error) {
|
||||
for key, value := range container.Config.Labels {
|
||||
if key == label {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("Label not found:" + label)
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) getLabels(container docker.Container, labels []string) (map[string]string, error) {
|
||||
foundLabels := map[string]string{}
|
||||
for _, label := range labels {
|
||||
if foundLabel, err := provider.getLabel(container, label); err != nil {
|
||||
return nil, errors.New("Label not found: " + label)
|
||||
} else {
|
||||
foundLabels[label] = foundLabel
|
||||
}
|
||||
}
|
||||
return foundLabels, nil
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) GetFrontendValue(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.frontend.value"); err == nil {
|
||||
return label
|
||||
}
|
||||
return provider.getEscapedName(container.Name) + "." + provider.Domain
|
||||
}
|
||||
|
||||
func (provider *DockerProvider) GetFrontendRule(container docker.Container) string {
|
||||
if label, err := provider.getLabel(container, "traefik.frontend.rule"); err == nil {
|
||||
return label
|
||||
}
|
||||
return "Host"
|
||||
}
|
1
docs/.dockerignore
Normal file
@ -0,0 +1 @@
|
||||
site/
|
11
docs/.markdownlint.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"no-hard-tabs": false,
|
||||
"MD007": { "indent": 4 },
|
||||
"MD009": false,
|
||||
"MD013": false,
|
||||
"MD024": false,
|
||||
"MD026": false,
|
||||
"MD033": false,
|
||||
"MD034": false,
|
||||
"MD036": false
|
||||
}
|
1
docs/CNAME
Normal file
@ -0,0 +1 @@
|
||||
docs.traefik.io
|
52
docs/Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
#######
|
||||
# This Makefile contains all targets related to the documentation
|
||||
#######
|
||||
|
||||
DOCS_VERIFY_SKIP ?= false
|
||||
DOCS_LINT_SKIP ?= false
|
||||
|
||||
TRAEFIK_DOCS_BUILD_IMAGE ?= traefik-docs
|
||||
TRAEFIK_DOCS_CHECK_IMAGE ?= $(TRAEFIK_DOCS_BUILD_IMAGE)-check
|
||||
|
||||
SITE_DIR := $(CURDIR)/site
|
||||
|
||||
DOCKER_RUN_DOC_PORT := 8000
|
||||
DOCKER_RUN_DOC_MOUNTS := -v $(CURDIR):/mkdocs
|
||||
DOCKER_RUN_DOC_OPTS := --rm $(DOCKER_RUN_DOC_MOUNTS) -p $(DOCKER_RUN_DOC_PORT):8000
|
||||
|
||||
# Default: generates the documentation into $(SITE_DIR)
|
||||
docs: docs-clean docs-image docs-lint docs-build docs-verify
|
||||
|
||||
# Writer Mode: build and serve docs on http://localhost:8000 with livereload
|
||||
docs-serve: docs-image
|
||||
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOCS_BUILD_IMAGE) mkdocs serve
|
||||
|
||||
# Utilities Targets for each step
|
||||
docs-image:
|
||||
docker build -t $(TRAEFIK_DOCS_BUILD_IMAGE) -f docs.Dockerfile ./
|
||||
|
||||
docs-build: docs-image
|
||||
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOCS_BUILD_IMAGE) sh -c "mkdocs build \
|
||||
&& chown -R $(shell id -u):$(shell id -g) ./site"
|
||||
|
||||
docs-verify: docs-build
|
||||
@if [ "$(DOCS_VERIFY_SKIP)" != "true" ]; then \
|
||||
docker build -t $(TRAEFIK_DOCS_CHECK_IMAGE) -f check.Dockerfile ./; \
|
||||
docker run --rm -v $(CURDIR):/app $(TRAEFIK_DOCS_CHECK_IMAGE) /verify.sh; \
|
||||
else \
|
||||
echo "DOCS_VERIFY_SKIP is true: no verification done."; \
|
||||
fi
|
||||
|
||||
docs-lint:
|
||||
@if [ "$(DOCS_LINT_SKIP)" != "true" ]; then \
|
||||
docker build -t $(TRAEFIK_DOCS_CHECK_IMAGE) -f check.Dockerfile ./ && \
|
||||
docker run --rm -v $(CURDIR):/app $(TRAEFIK_DOCS_CHECK_IMAGE) /lint.sh; \
|
||||
else \
|
||||
echo "DOCS_LINT_SKIP is true: no linting done."; \
|
||||
fi
|
||||
|
||||
docs-clean:
|
||||
rm -rf $(SITE_DIR)
|
||||
|
||||
.PHONY: all docs-verify docs docs-clean docs-build docs-lint
|
43
docs/check.Dockerfile
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
FROM alpine:3.9 as alpine
|
||||
|
||||
# The "build-dependencies" virtual package provides build tools for html-proofer installation.
|
||||
# It compile ruby-nokogiri, because alpine native version is always out of date
|
||||
# This virtual package is cleaned at the end.
|
||||
RUN apk --no-cache --no-progress add \
|
||||
libcurl \
|
||||
ruby \
|
||||
ruby-bigdecimal \
|
||||
ruby-etc \
|
||||
ruby-ffi \
|
||||
ruby-json \
|
||||
&& apk add --no-cache --virtual build-dependencies \
|
||||
build-base \
|
||||
libcurl \
|
||||
libxml2-dev \
|
||||
libxslt-dev \
|
||||
ruby-dev \
|
||||
&& gem install --no-document html-proofer -v 3.10.2 \
|
||||
&& apk del build-dependencies
|
||||
|
||||
# After Ruby, some NodeJS YAY!
|
||||
RUN apk --no-cache --no-progress add \
|
||||
git \
|
||||
nodejs \
|
||||
npm \
|
||||
&& npm install markdownlint@0.12.0 markdownlint-cli@0.13.0 --global
|
||||
|
||||
# Finally the shell tools we need for later
|
||||
# tini helps to terminate properly all the parallelized tasks when sending CTRL-C
|
||||
RUN apk --no-cache --no-progress add \
|
||||
ca-certificates \
|
||||
curl \
|
||||
tini
|
||||
|
||||
COPY ./scripts/verify.sh /verify.sh
|
||||
COPY ./scripts/lint.sh /lint.sh
|
||||
|
||||
WORKDIR /app
|
||||
VOLUME ["/tmp","/app"]
|
||||
|
||||
ENTRYPOINT ["/sbin/tini","-g","sh"]
|
BIN
docs/content/assets/img/architecture-overview.png
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
docs/content/assets/img/entrypoints.png
Normal file
After Width: | Height: | Size: 376 KiB |
BIN
docs/content/assets/img/middleware/addprefix.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
docs/content/assets/img/middleware/authforward.png
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
docs/content/assets/img/middleware/basicauth.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
docs/content/assets/img/middleware/buffering.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
docs/content/assets/img/middleware/chain.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
docs/content/assets/img/middleware/circuitbreaker.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
docs/content/assets/img/middleware/compress.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
docs/content/assets/img/middleware/digestauth.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
docs/content/assets/img/middleware/errorpages.png
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
docs/content/assets/img/middleware/headers.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
docs/content/assets/img/middleware/inflightreq.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
docs/content/assets/img/middleware/ipwhitelist.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
docs/content/assets/img/middleware/overview.png
Normal file
After Width: | Height: | Size: 307 KiB |
BIN
docs/content/assets/img/providers.png
Normal file
After Width: | Height: | Size: 377 KiB |
BIN
docs/content/assets/img/providers/docker.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
docs/content/assets/img/providers/rancher.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
docs/content/assets/img/quickstart-diagram.png
Normal file
After Width: | Height: | Size: 289 KiB |
BIN
docs/content/assets/img/routers.png
Normal file
After Width: | Height: | Size: 354 KiB |
BIN
docs/content/assets/img/services.png
Normal file
After Width: | Height: | Size: 339 KiB |
BIN
docs/content/assets/img/static-dynamic-configuration.png
Normal file
After Width: | Height: | Size: 378 KiB |
BIN
docs/content/assets/img/traefik-architecture.png
Normal file
After Width: | Height: | Size: 452 KiB |
BIN
docs/content/assets/img/traefik-concepts-1.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
docs/content/assets/img/traefik-concepts-2.png
Normal file
After Width: | Height: | Size: 209 KiB |
BIN
docs/content/assets/img/traefik.icon.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
docs/content/assets/img/traefik.logo.png
Normal file
After Width: | Height: | Size: 34 KiB |
4
docs/content/assets/img/user-guides/grpc.svg
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
docs/content/assets/img/webui-dashboard.png
Normal file
After Width: | Height: | Size: 125 KiB |
4
docs/content/assets/js/extra.js
Normal file
@ -0,0 +1,4 @@
|
||||
/* Highlight */
|
||||
(function(hljs) {
|
||||
hljs.initHighlightingOnLoad();
|
||||
})(hljs);
|
24
docs/content/assets/js/hljs/LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2006, Ivan Sagalaev
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of highlight.js nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2
docs/content/assets/js/hljs/highlight.pack.js
Normal file
96
docs/content/assets/styles/atom-one-light.css
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
Atom One Light by Daniel Gamage
|
||||
Original One Light Syntax theme from https://github.com/atom/one-light-syntax
|
||||
|
||||
base: #fafafa
|
||||
mono-1: #383a42
|
||||
mono-2: #686b77
|
||||
mono-3: #a0a1a7
|
||||
hue-1: #0184bb
|
||||
hue-2: #4078f2
|
||||
hue-3: #a626a4
|
||||
hue-4: #50a14f
|
||||
hue-5: #e45649
|
||||
hue-5-2: #c91243
|
||||
hue-6: #986801
|
||||
hue-6-2: #c18401
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #383a42;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #a0a1a7;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-doctag,
|
||||
.hljs-keyword,
|
||||
.hljs-formula {
|
||||
color: #a626a4;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name,
|
||||
.hljs-selector-tag,
|
||||
.hljs-deletion,
|
||||
.hljs-subst {
|
||||
color: #e45649;
|
||||
}
|
||||
|
||||
.hljs-literal {
|
||||
color: #0184bb;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-regexp,
|
||||
.hljs-addition,
|
||||
.hljs-attribute,
|
||||
.hljs-meta-string {
|
||||
color: #50a14f;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-class .hljs-title {
|
||||
color: #c18401;
|
||||
}
|
||||
|
||||
.hljs-attr,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-number {
|
||||
color: #986801;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-link,
|
||||
.hljs-meta,
|
||||
.hljs-selector-id,
|
||||
.hljs-title {
|
||||
color: #4078f2;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
63
docs/content/assets/styles/extra.css
Normal file
@ -0,0 +1,63 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Noto+Sans|Noto+Serif');
|
||||
|
||||
.md-logo img {
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/* Fix for Chrome */
|
||||
.md-typeset__table td code {
|
||||
word-break: unset;
|
||||
}
|
||||
|
||||
.md-typeset__table tr :nth-child(1) {
|
||||
word-wrap: break-word;
|
||||
max-width: 30em;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: bold !important;
|
||||
color: rgba(0,0,0,.9) !important;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.md-typeset h5 {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
color: #8D909F;
|
||||
}
|
||||
|
||||
p.subtitle {
|
||||
color: rgba(0,0,0,.54);
|
||||
padding-top: 0;
|
||||
margin-top: -2em;
|
||||
font-weight: bold;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item {
|
||||
list-style-type: none !important;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item input[type="checkbox"] {
|
||||
margin: 0 4px 0.25em -20px;
|
||||
vertical-align: middle;
|
||||
}
|
10
docs/content/contributing/advocating.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Advocating
|
||||
|
||||
Spread the Love & Tell Us about It
|
||||
{: .subtitle }
|
||||
|
||||
There are many ways to contribute to the project, and there is one that always spark joy: when we see/read about users talking about how Traefik helps them solve their problems.
|
||||
|
||||
If you're talking about Traefik, [let us know](https://blog.containo.us/spread-the-love-ba5a40aa72e7) and we'll promote your enthusiasm!
|
||||
|
||||
Also, if you've written about Traefik or shared useful information you'd like to promote, feel free to add links in the [dedicated wiki page on Github](https://github.com/containous/traefik/wiki/Awesome-Traefik).
|
173
docs/content/contributing/building-testing.md
Normal file
@ -0,0 +1,173 @@
|
||||
# Building and Testing
|
||||
|
||||
Compile and Test Your Own Traefik!
|
||||
{: .subtitle }
|
||||
|
||||
So you want to build your own Traefik binary from the sources?
|
||||
Let's see how.
|
||||
|
||||
## 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 `dep` dependency management tool is required.
|
||||
|
||||
### Method 1: Using `Docker` and `Makefile`
|
||||
|
||||
Run make with the `binary` target.
|
||||
This will create binaries for the Linux platform in the `dist` folder.
|
||||
|
||||
```bash
|
||||
$ make binary
|
||||
docker build -t traefik-webui -f webui/Dockerfile webui
|
||||
Sending build context to Docker daemon 2.686MB
|
||||
Step 1/11 : FROM node:8.15.0
|
||||
---> 1f6c34f7921c
|
||||
[...]
|
||||
Successfully built ce4ff439c06a
|
||||
Successfully tagged traefik-webui:latest
|
||||
[...]
|
||||
docker build -t "traefik-dev:4475--feature-documentation" -f build.Dockerfile .
|
||||
Sending build context to Docker daemon 279MB
|
||||
Step 1/10 : FROM golang:1.13-alpine
|
||||
---> f4bfb3d22bda
|
||||
[...]
|
||||
Successfully built 5c3c1a911277
|
||||
Successfully tagged traefik-dev:4475--feature-documentation
|
||||
docker run -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock" -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -e VERBOSE -e VERSION -e CODENAME -e TESTDIRS -e CI -e CONTAINER=DOCKER -v "/home/ldez/sources/go/src/github.com/containous/traefik/"dist":/go/src/github.com/containous/traefik/"dist"" "traefik-dev:4475--feature-documentation" ./script/make.sh generate binary
|
||||
---> Making bundle: generate (in .)
|
||||
removed 'autogen/genstatic/gen.go'
|
||||
|
||||
---> Making bundle: binary (in .)
|
||||
|
||||
$ ls dist/
|
||||
traefik*
|
||||
```
|
||||
|
||||
The following targets can be executed outside Docker by setting the variable `PRE_TARGET` to an empty string (we don't recommend that):
|
||||
|
||||
- `test-unit`
|
||||
- `test-integration`
|
||||
- `validate`
|
||||
- `binary` (the webUI is still generated by using Docker)
|
||||
|
||||
ex:
|
||||
|
||||
```bash
|
||||
PRE_TARGET= make test-unit
|
||||
```
|
||||
|
||||
### Method 2: Using `go`
|
||||
|
||||
Requirements:
|
||||
|
||||
- `go` v1.13+
|
||||
- environment variable `GO111MODULE=on`
|
||||
|
||||
!!! tip "Source Directory"
|
||||
|
||||
It is recommended that you clone Traefik into the `~/go/src/github.com/containous/traefik` directory.
|
||||
This is the official golang workspace hierarchy that will allow dependencies to be properly resolved.
|
||||
|
||||
!!! note "Environment"
|
||||
|
||||
Set your `GOPATH` and `PATH` variable to be set to `~/go` via:
|
||||
|
||||
```bash
|
||||
export GOPATH=~/go
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
For convenience, add `GOPATH` and `PATH` to your `.bashrc` or `.bash_profile`
|
||||
|
||||
Verify your environment is setup properly by running `$ go env`.
|
||||
Depending on your OS and environment, you should see an output similar to:
|
||||
|
||||
```bash
|
||||
GOARCH="amd64"
|
||||
GOBIN=""
|
||||
GOEXE=""
|
||||
GOHOSTARCH="amd64"
|
||||
GOHOSTOS="linux"
|
||||
GOOS="linux"
|
||||
GOPATH="/home/<yourusername>/go"
|
||||
GORACE=""
|
||||
## ... and the list goes on
|
||||
```
|
||||
|
||||
#### Build Traefik
|
||||
|
||||
Once you've set up your go environment and cloned the source repository, you can build Traefik.
|
||||
Beforehand, you need to get `go-bindata` (the first time) in order to be able to use the `go generate` command (which is part of the build process).
|
||||
|
||||
```bash
|
||||
cd ~/go/src/github.com/containous/traefik
|
||||
|
||||
# Get go-bindata. (Important: the ellipses are required.)
|
||||
GO111MODULE=off go get github.com/containous/go-bindata/...
|
||||
|
||||
# Let's build
|
||||
|
||||
# generate
|
||||
# (required to merge non-code components into the final binary, such as the web dashboard and the provider's templates)
|
||||
go generate
|
||||
|
||||
# Standard go build
|
||||
go build ./cmd/traefik
|
||||
```
|
||||
|
||||
You will find the Traefik executable (`traefik`) in the `~/go/src/github.com/containous/traefik` directory.
|
||||
|
||||
### Updating the templates
|
||||
|
||||
If you happen to update the provider's templates (located in `/templates`), you must run `go generate` to update the `autogen` package.
|
||||
|
||||
## Testing
|
||||
|
||||
### Method 1: `Docker` and `make`
|
||||
|
||||
Run unit tests using the `test-unit` target.
|
||||
Run integration tests using the `test-integration` target.
|
||||
Run all tests (unit and integration) using the `test` target.
|
||||
|
||||
```bash
|
||||
$ make test-unit
|
||||
docker build -t "traefik-dev:your-feature-branch" -f build.Dockerfile .
|
||||
# […]
|
||||
docker run --rm -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -v "/home/user/go/src/github/containous/traefik/dist:/go/src/github.com/containous/traefik/dist" "traefik-dev:your-feature-branch" ./script/make.sh generate test-unit
|
||||
---> Making bundle: generate (in .)
|
||||
removed 'gen.go'
|
||||
|
||||
---> Making bundle: test-unit (in .)
|
||||
+ go test -cover -coverprofile=cover.out .
|
||||
ok github.com/containous/traefik 0.005s coverage: 4.1% of statements
|
||||
|
||||
Test success
|
||||
```
|
||||
|
||||
For development purposes, you can specify which tests to run by using (only works the `test-integration` target):
|
||||
|
||||
```bash
|
||||
# Run every tests in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite" make test-integration
|
||||
|
||||
# Run the test "MyTest" in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite.MyTest" make test-integration
|
||||
|
||||
# Run every tests starting with "My", in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite.My" make test-integration
|
||||
|
||||
# Run every tests ending with "Test", in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite.*Test" make test-integration
|
||||
```
|
||||
|
||||
More: https://labix.org/gocheck
|
||||
|
||||
### Method 2: `go`
|
||||
|
||||
Unit tests can be run from the cloned directory using `$ go test ./...` which should return `ok`, similar to:
|
||||
|
||||
```test
|
||||
ok _/home/user/go/src/github/containous/traefik 0.004s
|
||||
```
|
||||
|
||||
Integration tests must be run from the `integration/` directory and require the `-integration` switch: `$ cd integration && go test -integration ./...`.
|
98
docs/content/contributing/data-collection.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Data Collection
|
||||
|
||||
Understanding How Traefik is Being Used
|
||||
{: .subtitle }
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Understanding how you use Traefik is very important to us: it helps us improve the solution in many different ways.
|
||||
For this very reason, the sendAnonymousUsage option is mandatory: we want you to take time to consider whether or not you wish to share anonymous data with us so we can benefit from your experience and use cases.
|
||||
|
||||
!!! example "Enabling Data Collection"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[global]
|
||||
# Send anonymous usage data
|
||||
sendAnonymousUsage = true
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
global:
|
||||
# Send anonymous usage data
|
||||
sendAnonymousUsage: true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# Send anonymous usage data
|
||||
--global.sendAnonymousUsage
|
||||
```
|
||||
|
||||
## Collected Data
|
||||
|
||||
This feature comes from the public proposal [here](https://github.com/containous/traefik/issues/2369).
|
||||
|
||||
In order to help us learn more about how Traefik is being used and improve it, we collect anonymous usage statistics from running instances.
|
||||
Those data help us prioritize our developments and focus on what's important for our users (for example, which provider is popular, and which is not).
|
||||
|
||||
### What's collected / when ?
|
||||
|
||||
Once a day (the first call begins 10 minutes after the start of Traefik), we collect:
|
||||
|
||||
- the Traefik version number
|
||||
- a hash of the configuration
|
||||
- an **anonymized version** of the static configuration (token, user name, password, URL, IP, domain, email, etc, are removed).
|
||||
|
||||
!!! note
|
||||
We do not collect the dynamic configuration information (routers & services).
|
||||
We do not collect these data to run advertising programs.
|
||||
We do not sell these data to third-parties.
|
||||
|
||||
### Example of Collected Data
|
||||
|
||||
??? example "Original configuration"
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":80"
|
||||
|
||||
[api]
|
||||
|
||||
[providers.docker]
|
||||
endpoint = "tcp://10.10.10.10:2375"
|
||||
exposedByDefault = true
|
||||
swarmMode = true
|
||||
|
||||
[providers.docker.TLS]
|
||||
ca = "dockerCA"
|
||||
cert = "dockerCert"
|
||||
key = "dockerKey"
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
??? example "Resulting Obfuscated Configuration"
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":80"
|
||||
|
||||
[api]
|
||||
|
||||
[providers.docker]
|
||||
endpoint = "xxxx"
|
||||
exposedByDefault = true
|
||||
swarmMode = true
|
||||
|
||||
[providers.docker.TLS]
|
||||
ca = "xxxx"
|
||||
cert = "xxxx"
|
||||
key = "xxxx"
|
||||
insecureSkipVerify = false
|
||||
```
|
||||
|
||||
## The Code for Data Collection
|
||||
|
||||
If you want to dig into more details, here is the source code of the collecting system: [collector.go](https://github.com/containous/traefik/blob/master/pkg/collector/collector.go)
|
||||
|
||||
By default we anonymize all configuration fields, except fields tagged with `export=true`.
|
100
docs/content/contributing/documentation.md
Normal file
@ -0,0 +1,100 @@
|
||||
# Documentation
|
||||
|
||||
Features Are Better When You Know How to Use Them
|
||||
{: .subtitle }
|
||||
|
||||
You've found something unclear in the documentation and want to give a try at explaining it better?
|
||||
Let's see how.
|
||||
|
||||
## Building Documentation
|
||||
|
||||
### General
|
||||
|
||||
This [documentation](https://docs.traefik.io/) is built with [mkdocs](https://mkdocs.org/).
|
||||
|
||||
### Method 1: `Docker` and `make`
|
||||
|
||||
You can build the documentation and test it locally (with live reloading), using the `docs` target:
|
||||
|
||||
```bash
|
||||
$ make docs
|
||||
docker build -t traefik-docs -f docs.Dockerfile .
|
||||
# […]
|
||||
docker run --rm -v /home/user/go/github/containous/traefik:/mkdocs -p 8000:8000 traefik-docs mkdocs serve
|
||||
# […]
|
||||
[I 170828 20:47:48 server:283] Serving on http://0.0.0.0:8000
|
||||
[I 170828 20:47:48 handlers:60] Start watching changes
|
||||
[I 170828 20:47:48 handlers:62] Start detecting changes
|
||||
```
|
||||
|
||||
!!! tip "Default URL"
|
||||
|
||||
Your local documentation server will run by default on [http://127.0.0.1:8000](http://127.0.0.1:8000).
|
||||
|
||||
If you only want to build the documentation without serving it locally, you can use the following command:
|
||||
|
||||
```bash
|
||||
$ make docs-build
|
||||
...
|
||||
```
|
||||
|
||||
### Method 2: `mkdocs`
|
||||
|
||||
First, make sure you have `python` and `pip` installed.
|
||||
|
||||
```bash
|
||||
$ python --version
|
||||
Python 2.7.2
|
||||
$ pip --version
|
||||
pip 1.5.2
|
||||
```
|
||||
|
||||
Then, install mkdocs with `pip`.
|
||||
|
||||
```bash
|
||||
pip install --user -r requirements.txt
|
||||
```
|
||||
|
||||
To build the documentation locally and serve it locally, run `mkdocs serve` from the root directory.
|
||||
This will start a local server.
|
||||
|
||||
```bash
|
||||
$ mkdocs serve
|
||||
INFO - Building documentation...
|
||||
INFO - Cleaning site directory
|
||||
[I 160505 22:31:24 server:281] Serving on http://127.0.0.1:8000
|
||||
[I 160505 22:31:24 handlers:59] Start watching changes
|
||||
[I 160505 22:31:24 handlers:61] Start detecting changes
|
||||
```
|
||||
|
||||
### Check the Documentation
|
||||
|
||||
To check that the documentation meets standard expectations (no dead links, html markup validity, ...), use the `docs-verify` target.
|
||||
|
||||
```bash
|
||||
$ make docs-verify
|
||||
docker build -t traefik-docs-verify ./script/docs-verify-docker-image ## Build Validator image
|
||||
...
|
||||
docker run --rm -v /home/travis/build/containous/traefik:/app traefik-docs-verify ## Check for dead links and w3c compliance
|
||||
=== Checking HTML content...
|
||||
Running ["HtmlCheck", "ImageCheck", "ScriptCheck", "LinkCheck"] on /app/site/basics/index.html on *.html...
|
||||
```
|
||||
|
||||
!!! note "Clean & Verify"
|
||||
|
||||
If you've made changes to the documentation, it's safter to clean it before verifying it.
|
||||
|
||||
```bash
|
||||
$ make docs-clean docs-verify
|
||||
...
|
||||
```
|
||||
|
||||
!!! note "Disabling Documentation Verification"
|
||||
|
||||
Verification can be disabled by setting the environment variable `DOCS_VERIFY_SKIP` to `true`:
|
||||
|
||||
```shell
|
||||
DOCS_VERIFY_SKIP=true make docs-verify
|
||||
...
|
||||
DOCS_LINT_SKIP is true: no linting done.
|
||||
```
|
176
docs/content/contributing/maintainers.md
Normal file
@ -0,0 +1,176 @@
|
||||
# Maintainers
|
||||
|
||||
## The team
|
||||
|
||||
* Emile Vauge [@emilevauge](https://github.com/emilevauge)
|
||||
* Vincent Demeester [@vdemeester](https://github.com/vdemeester)
|
||||
* Ed Robinson [@errm](https://github.com/errm)
|
||||
* Daniel Tomcej [@dtomcej](https://github.com/dtomcej)
|
||||
* Manuel Zapf [@SantoDE](https://github.com/SantoDE)
|
||||
* Timo Reimann [@timoreimann](https://github.com/timoreimann)
|
||||
* Ludovic Fernandez [@ldez](https://github.com/ldez)
|
||||
* Julien Salleyron [@juliens](https://github.com/juliens)
|
||||
* Nicolas Mengin [@nmengin](https://github.com/nmengin)
|
||||
* Marco Jantke [@marco-jantke](https://github.com/marco-jantke)
|
||||
* Michaël Matur [@mmatur](https://github.com/mmatur)
|
||||
* Gérald Croës [@geraldcroes](https://github.com/geraldcroes)
|
||||
* Jean-Baptiste Doumenjou [@jbdoumenjou](https://github.com/jbdoumenjou)
|
||||
* Damien Duportal [@dduportal](https://github.com/dduportal)
|
||||
* Mathieu Lonjaret [@mpl](https://github.com/mpl)
|
||||
|
||||
## Contributions Daily Meeting
|
||||
|
||||
* 3 Maintainers should attend to a Contributions Daily Meeting where we sort and label new issues ([is:issue label:status/0-needs-triage](https://github.com/containous/traefik/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Astatus%2F0-needs-triage+)), and review every Pull Requests
|
||||
* Every pull request should be checked during the Contributions Daily Meeting
|
||||
* Even if it’s already assigned
|
||||
* Even PR labelled with `contributor/waiting-for-corrections` or `contributor/waiting-for-feedback`
|
||||
* Issues labeled with `priority/P0` and `priority/P1` should be assigned.
|
||||
* Modifying an issue or a pull request (labels, assignees, milestone) is only possible:
|
||||
* During the Contributions Daily Meeting
|
||||
* By an assigned maintainer
|
||||
* In case of emergency, if a change proposal is approved by 2 other maintainers (on Slack, Discord, Discourse, etc)
|
||||
|
||||
## PR review process:
|
||||
|
||||
* The status `needs-design-review` is only used in complex/heavy/tricky PRs.
|
||||
* From `1` to `2`: 1 comment that says “design LGTM” (by a senior maintainer).
|
||||
* From `2` to `3`: 3 LGTM approvals by any maintainer.
|
||||
* If needed, a specific maintainer familiar with a particular domain can be requested for the review.
|
||||
* If a PR has been implemented in pair programming, one peer's LGTM goes into the review for free
|
||||
* Amending someone else's pull request is authorized only in emergency, if a rebase is needed, or if the initial contributor is silent
|
||||
|
||||
We use [PRM](https://github.com/ldez/prm) to manage locally pull requests.
|
||||
|
||||
## Bots
|
||||
|
||||
### [Myrmica Lobicornis](https://github.com/containous/lobicornis/)
|
||||
|
||||
Update and Merge Pull Request.
|
||||
|
||||
The maintainer giving the final LGTM must add the `status/3-needs-merge` label to trigger the merge bot.
|
||||
|
||||
By default, a squash-rebase merge will be carried out.
|
||||
To preserve commits, add `bot/merge-method-rebase` before `status/3-needs-merge`.
|
||||
|
||||
The status `status/4-merge-in-progress` is only used by the bot.
|
||||
|
||||
If the bot is not able to perform the merge, the label `bot/need-human-merge` is added.
|
||||
In such a situation, solve the conflicts/CI/... and then remove the label `bot/need-human-merge`.
|
||||
|
||||
To prevent the bot from automatically merging a PR, add the label `bot/no-merge`.
|
||||
|
||||
The label `bot/light-review` decreases the number of required LGTM from 3 to 1.
|
||||
|
||||
This label is used when:
|
||||
|
||||
* Updating the vendors from previously reviewed PRs
|
||||
* Merging branches into the master
|
||||
* Preparing the release
|
||||
|
||||
### [Myrmica Bibikoffi](https://github.com/containous/bibikoffi/)
|
||||
|
||||
* closes stale issues [cron]
|
||||
* use some criterion as number of days between creation, last update, labels, ...
|
||||
|
||||
### [Myrmica Aloba](https://github.com/containous/aloba)
|
||||
|
||||
Manage GitHub labels.
|
||||
|
||||
* Add labels on new PR [GitHub WebHook]
|
||||
* Add milestone to a new PR based on a branch version (1.4, 1.3, ...) [GitHub WebHook]
|
||||
* Add and remove `contributor/waiting-for-corrections` label when a review request changes [GitHub WebHook]
|
||||
* Weekly report of PR status on Slack (CaptainPR) [cron]
|
||||
|
||||
## Labels
|
||||
|
||||
A maintainer that looks at an issue/PR must define its `kind/*`, `area/*`, and `status/*`.
|
||||
|
||||
### Status - Workflow
|
||||
|
||||
The `status/*` labels represent the desired state in the workflow.
|
||||
|
||||
* `status/0-needs-triage`: all the new issues and PRs have this status. _[bot only]_
|
||||
* `status/1-needs-design-review`: needs a design review. **(only for PR)**
|
||||
* `status/2-needs-review`: needs a code/documentation review. **(only for PR)**
|
||||
* `status/3-needs-merge`: ready to merge. **(only for PR)**
|
||||
* `status/4-merge-in-progress`: merge is in progress. _[bot only]_
|
||||
|
||||
### Contributor
|
||||
|
||||
* `contributor/need-more-information`: we need more information from the contributor in order to analyze a problem.
|
||||
* `contributor/waiting-for-feedback`: we need the contributor to give us feedback.
|
||||
* `contributor/waiting-for-corrections`: we need the contributor to take actions in order to move forward with a PR. **(only for PR)** _[bot, humans]_
|
||||
* `contributor/needs-resolve-conflicts`: use it only when there is some conflicts (and an automatic rebase is not possible). **(only for PR)** _[bot, humans]_
|
||||
|
||||
### Kind
|
||||
|
||||
* `kind/enhancement`: a new or improved feature.
|
||||
* `kind/question`: a question. **(only for issue)**
|
||||
* `kind/proposal`: a proposal that needs to be discussed.
|
||||
* _Proposal issues_ are design proposals
|
||||
* _Proposal PRs_ are technical prototypes that need to be refined with multiple contributors.
|
||||
|
||||
* `kind/bug/possible`: a possible bug that needs analysis before it is confirmed or fixed. **(only for issues)**
|
||||
* `kind/bug/confirmed`: a confirmed bug (reproducible). **(only for issues)**
|
||||
* `kind/bug/fix`: a bug fix. **(only for PR)**
|
||||
|
||||
### Resolution
|
||||
|
||||
* `resolution/duplicate`: a duplicate issue/PR.
|
||||
* `resolution/declined`: declined (Rule #1 of open-source: no is temporary, yes is forever).
|
||||
* `WIP`: Work In Progress. **(only for PR)**
|
||||
|
||||
### Platform
|
||||
|
||||
* `platform/windows`: Windows related.
|
||||
|
||||
### Area
|
||||
|
||||
* `area/acme`: ACME related.
|
||||
* `area/api`: Traefik API related.
|
||||
* `area/authentication`: Authentication related.
|
||||
* `area/cluster`: Traefik clustering related.
|
||||
* `area/documentation`: Documentation related.
|
||||
* `area/infrastructure`: CI or Traefik building scripts related.
|
||||
* `area/healthcheck`: Health-check related.
|
||||
* `area/logs`: Logs related.
|
||||
* `area/middleware`: Middleware related.
|
||||
* `area/middleware/metrics`: Metrics related. (Prometheus, StatsD, ...)
|
||||
* `area/middleware/tracing`: Tracing related. (Jaeger, Zipkin, ...)
|
||||
* `area/oxy`: Oxy related.
|
||||
* `area/provider`: related to all providers.
|
||||
* `area/provider/boltdb`: Boltd DB related.
|
||||
* `area/provider/consul`: Consul related.
|
||||
* `area/provider/docker`: Docker and Swarm related.
|
||||
* `area/provider/ecs`: ECS related.
|
||||
* `area/provider/etcd`: Etcd related.
|
||||
* `area/provider/eureka`: Eureka related.
|
||||
* `area/provider/file`: file provider related.
|
||||
* `area/provider/k8s`: Kubernetes related.
|
||||
* `area/provider/kv`: KV related.
|
||||
* `area/provider/marathon`: Marathon related.
|
||||
* `area/provider/mesos`: Mesos related.
|
||||
* `area/provider/rancher`: Rancher related.
|
||||
* `area/provider/servicefabric`: Azure service fabric related.
|
||||
* `area/provider/zk`: Zoo Keeper related.
|
||||
* `area/rules`: Rules related.
|
||||
* `area/server`: Server related.
|
||||
* `area/sticky-session`: Sticky session related.
|
||||
* `area/tls`: TLS related.
|
||||
* `area/websocket`: WebSocket related.
|
||||
* `area/webui`: Web UI related.
|
||||
|
||||
### Issues Priority
|
||||
|
||||
* `priority/P0`: needs hot fix.
|
||||
* `priority/P1`: need to be fixed in next release.
|
||||
* `priority/P2`: need to be fixed in the future.
|
||||
* `priority/P3`: maybe.
|
||||
|
||||
### PR size
|
||||
|
||||
Automatically set by a bot.
|
||||
|
||||
* `size/S`: small PR.
|
||||
* `size/M`: medium PR.
|
||||
* `size/L`: Large PR.
|
44
docs/content/contributing/submitting-issues.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Submitting Issues
|
||||
|
||||
Help Us Help You!
|
||||
{: .subtitle }
|
||||
|
||||
We use the [GitHub issue tracker](https://github.com/containous/traefik/issues) to keep track of issues in Traefik.
|
||||
|
||||
The process of sorting and checking the issues is a daunting task, and requires a lot of work (more than an hour a day ... just for sorting).
|
||||
To save us some time and get quicker feedback, be sure to follow the guide lines below.
|
||||
|
||||
!!! important "Getting Help Vs Reporting an Issue"
|
||||
|
||||
The issue tracker is not a general support forum, but a place to report bugs and asks for new features.
|
||||
|
||||
For end-user related support questions, try using first:
|
||||
|
||||
- the Traefik community forum: [](https://community.containo.us/)
|
||||
|
||||
## Issue Title
|
||||
|
||||
The title must be short and descriptive. (~60 characters)
|
||||
|
||||
## Description
|
||||
|
||||
Follow the [issue template](https://github.com/containous/traefik/blob/master/.github/ISSUE_TEMPLATE.md) as much as possible.
|
||||
|
||||
Explain us in which conditions you encountered the issue, what is your context.
|
||||
|
||||
Remain as clear and concise as possible
|
||||
|
||||
Take time to polish the format of your message so we'll enjoy reading it and working on it.
|
||||
Help the readers focus on what matters, and help them understand the structure of your message (see the [Github Markdown Syntax](https://help.github.com/articles/github-flavored-markdown)).
|
||||
|
||||
## Feature Request
|
||||
|
||||
Traefik is an open-source project and aims to be the best edge router possible.
|
||||
|
||||
Remember when asking for new features that these must be useful to the majority (and not only useful in edge case scenarios, or hack-like setups).
|
||||
|
||||
Do you best to explain what you're looking for, and why it would improve Traefik for everyone.
|
||||
|
||||
## International English
|
||||
|
||||
Every maintainer / Traefik user is not a native English speaker, so if you feel sometimes that some messages sound rude, remember that it probably is a language barrier problem from someone willing to help you.
|
45
docs/content/contributing/submitting-pull-requests.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Submitting Pull Requests
|
||||
|
||||
A Quick Guide for Efficient Contributions
|
||||
{: .subtitle }
|
||||
|
||||
So you've decide to improve Traefik?
|
||||
Thank You!
|
||||
Now the last step is to submit your Pull Request in a way that makes sure it gets the attention it deserves.
|
||||
|
||||
Let's go though the classic pitfalls to make sure everything is right.
|
||||
|
||||
## Title
|
||||
|
||||
The title must be short and descriptive. (~60 characters)
|
||||
|
||||
## Description
|
||||
|
||||
Follow the [pull request template](https://github.com/containous/traefik/blob/master/.github/PULL_REQUEST_TEMPLATE.md) as much as possible.
|
||||
|
||||
Explain the conditions which led you to write this PR: give us context.
|
||||
The context should lead to something, an idea or a problem that you’re facing.
|
||||
|
||||
Remain clear and concise.
|
||||
|
||||
Take time to polish the format of your message so we'll enjoy reading it and working on it.
|
||||
Help the readers focus on what matters, and help them understand the structure of your message (see the [Github Markdown Syntax](https://help.github.com/articles/github-flavored-markdown)).
|
||||
|
||||
## PR Content
|
||||
|
||||
- Make it small.
|
||||
- One feature per Pull Request.
|
||||
- Write useful descriptions and titles.
|
||||
- Avoid re-formatting code that is not on the path of your PR.
|
||||
- Make sure the [code builds](building-testing.md).
|
||||
- Make sure [all tests pass](building-testing.md).
|
||||
- Add tests.
|
||||
- Address review comments in terms of additional commits (and don't amend/squash existing ones unless the PR is trivial).
|
||||
|
||||
!!! note "third-party dependencies"
|
||||
|
||||
If a PR involves changes to third-party dependencies, the commits pertaining to the vendor folder and the manifest/lock file(s) should be committed separated.
|
||||
|
||||
!!! tip "10 Tips for Better Pull Requests"
|
||||
|
||||
We enjoyed this article, maybe you will too! [10 tips for better pull requests](https://blog.ploeh.dk/2015/01/15/10-tips-for-better-pull-requests/).
|
27
docs/content/contributing/thank-you.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Thank You!
|
||||
|
||||
_You_ Made It
|
||||
{: .subtitle}
|
||||
|
||||
Traefik truly is an [open-source project](https://github.com/containous/traefik/),
|
||||
and wouldn't have become what it is today without the help of our [many contributors](https://github.com/containous/traefik/graphs/contributors) (at the time of writing this),
|
||||
not accounting for people having helped with issues, tests, comments, articles, ... or just enjoying it and letting others know.
|
||||
|
||||
So once again, thank you for your invaluable help on making Traefik such a good product.
|
||||
|
||||
!!! question "Where to Go Next?"
|
||||
If you want to:
|
||||
|
||||
- Propose and idea, request a feature a report a bug,
|
||||
read the page [Submitting Issues](./submitting-issues.md).
|
||||
- Discover how to make an efficient contribution,
|
||||
read the page [Submitting Pull Requests](./submitting-pull-requests.md).
|
||||
- Learn how to build and test Traefik,
|
||||
the page [Building and Testing](./building-testing.md) is for you.
|
||||
- Contribute to the documentation,
|
||||
read the related page [Documentation](./documentation.md).
|
||||
- Understand how do we learn about Traefik usage,
|
||||
read the [Data Collection](./data-collection.md) page.
|
||||
- Spread the love about Traefik, please check the [Advocating](./advocating.md) page.
|
||||
- Learn about who are the maintainers and how they work on the project,
|
||||
read the [Maintainers](./maintainers.md) page.
|
36
docs/content/getting-started/concepts.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Concepts
|
||||
|
||||
Everything You Need to Know
|
||||
{: .subtitle }
|
||||
|
||||
## Edge Router
|
||||
|
||||
Traefik is an _Edge Router_, it means that it's the door to your platform, and that it intercepts and routes every incoming request:
|
||||
it knows all the logic and every rule that determine which services handle which requests (based on the [path](../routing/routers/index.md#rule), the [host](../routing/routers/index.md#rule), [headers](../routing/routers/index.md#rule), [and so on](../routing/routers/index.md#rule) ...).
|
||||
|
||||

|
||||
|
||||
## Auto Service Discovery
|
||||
|
||||
Where traditionally edge routers (or reverse proxies) need a configuration file that contains every possible route to your services, Traefik gets them from the services themselves.
|
||||
|
||||
Deploying your services, you attach information that tells Traefik the characteristics of the requests the services can handle.
|
||||
|
||||

|
||||
|
||||
It means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time.
|
||||
The opposite is true: when you remove a service from your infrastructure, the route will disappear accordingly.
|
||||
|
||||
You no longer need to create and synchronize configuration files cluttered with IP addresses or other rules.
|
||||
|
||||
!!! note "Many different rules"
|
||||
|
||||
In the example above, we used the request [path](../routing/routers/index.md#rule) to determine which service was in charge, but of course you can use many other different [rules](../routing/routers/index.md#rule).
|
||||
|
||||
!!! note "Updating the requests"
|
||||
|
||||
In the [middleware](../middlewares/overview.md) section, you can learn about how to update the requests before forwarding them to the services.
|
||||
|
||||
!!! question "How does Traefik discover the services?"
|
||||
|
||||
Traefik is able to use your cluster API to discover the services and read the attached information. In Traefik, these connectors are called [providers](../providers/overview.md) because they _provide_ the configuration to Traefik. To learn more about them, read the [provider overview](../providers/overview.md) section.
|
88
docs/content/getting-started/configuration-overview.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Configuration Introduction
|
||||
|
||||
How the Magic Happens
|
||||
{: .subtitle }
|
||||
|
||||

|
||||
|
||||
Configuration in Traefik can refer to two different things:
|
||||
|
||||
- The fully dynamic routing configuration (referred to as the _dynamic configuration_)
|
||||
- The startup configuration (referred to as the _static configuration_)
|
||||
|
||||
Elements in the _static configuration_ set up connections to [providers](../providers/overview.md) and define the [entrypoints](../routing/entrypoints.md) Traefik will listen to (these elements don't change often).
|
||||
|
||||
The _dynamic configuration_ contains everything that defines how the requests are handled by your system.
|
||||
This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.
|
||||
|
||||
!!! warning "Incompatible Configuration"
|
||||
Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now.
|
||||
If you're testing out v2, please ensure you are using a v2 configuration.
|
||||
|
||||
## The Dynamic Configuration
|
||||
|
||||
Traefik gets its _dynamic configuration_ from [providers](../providers/overview.md): whether an orchestrator, a service registry, or a plain old configuration file. Since this configuration is specific to your infrastructure choices, we invite you to refer to the [dedicated section of this documentation](../providers/overview.md).
|
||||
|
||||
!!! Note
|
||||
|
||||
In the [Quick Start example](../getting-started/quick-start.md), the dynamic configuration comes from docker in the form of labels attached to your containers.
|
||||
|
||||
!!! Note
|
||||
|
||||
HTTPS Certificates also belong to the dynamic configuration. You can add / update / remove them without restarting your Traefik instance.
|
||||
|
||||
## The Static Configuration
|
||||
|
||||
There are three different, mutually exclusive, ways to define static configuration options in Traefik:
|
||||
|
||||
- In a configuration file
|
||||
- In the command-line arguments
|
||||
- As environment variables
|
||||
|
||||
These ways are evaluated in the order listed above.
|
||||
|
||||
If no value was provided for a given option, a default value applies.
|
||||
Moreover, if an option has sub-options, and any of these sub-options is not specified, a default value will apply as well.
|
||||
|
||||
For example, the `--providers.docker` option is enough by itself to enable the docker provider, even though sub-options like `--providers.docker.endpoint` exist.
|
||||
Once positioned, this option sets (and resets) all the default values of the sub-options of `--providers.docker`.
|
||||
|
||||
### Configuration File
|
||||
|
||||
At startup, Traefik searches for a file named `traefik.toml` (or `traefik.yml` or `traefik.yaml`) in:
|
||||
|
||||
- `/etc/traefik/`
|
||||
- `$XDG_CONFIG_HOME/`
|
||||
- `$HOME/.config/`
|
||||
- `.` (_the working directory_).
|
||||
|
||||
You can override this using the `configFile` argument.
|
||||
|
||||
```bash
|
||||
traefik --configFile=foo/bar/myconfigfile.toml
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
To get the list of all available arguments:
|
||||
|
||||
```bash
|
||||
traefik --help
|
||||
|
||||
# or
|
||||
|
||||
docker run traefik[:version] --help
|
||||
# ex: docker run traefik:2.0 --help
|
||||
```
|
||||
|
||||
All available arguments can also be found [here](../reference/static-configuration/cli.md).
|
||||
|
||||
### Environment Variables
|
||||
|
||||
All available environment variables can be found [here](../reference/static-configuration/env.md)
|
||||
|
||||
## Available Configuration Options
|
||||
|
||||
All the configuration options are documented in their related section.
|
||||
|
||||
You can browse the available features in the menu, the [providers](../providers/overview.md), or the [routing section](../routing/overview.md) to see them in action.
|
70
docs/content/getting-started/install-traefik.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Install Traefik
|
||||
|
||||
You can install Traefik with the following flavors:
|
||||
|
||||
* [Use the official Docker image](./#use-the-official-docker-image)
|
||||
* [Use the binary distribution](./#use-the-binary-distribution)
|
||||
* [Compile your binary from the sources](./#compile-your-binary-from-the-sources)
|
||||
|
||||
## Use the Official Docker Image
|
||||
|
||||
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with the [sample configuration file](https://raw.githubusercontent.com/containous/traefik/v2.0/traefik.sample.toml):
|
||||
|
||||
```shell
|
||||
docker run -d -p 8080:8080 -p 80:80 \
|
||||
-v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik:v2.0
|
||||
```
|
||||
|
||||
For more details, go to the [Docker provider documentation](../providers/docker.md)
|
||||
|
||||
!!! tip
|
||||
|
||||
* Prefer a fixed version than the latest that could be an unexpected version.
|
||||
ex: `traefik:v2.0.0`
|
||||
* Docker images comes in 2 flavors: scratch based or alpine based.
|
||||
* All the orchestrator using docker images could fetch the official Traefik docker image.
|
||||
|
||||
## Use the Binary Distribution
|
||||
|
||||
Grab the latest binary from the [releases](https://github.com/containous/traefik/releases) page.
|
||||
|
||||
??? tip "Check the integrity of the downloaded file"
|
||||
|
||||
```bash tab="Linux"
|
||||
# Compare this value to the one found in traefik-${traefik_version}_checksums.txt
|
||||
sha256sum ./traefik_${traefik_version}_linux_${arch}.tar.gz
|
||||
```
|
||||
|
||||
```bash tab="macOS"
|
||||
# Compare this value to the one found in traefik-${traefik_version}_checksums.txt
|
||||
shasum -a256 ./traefik_${traefik_version}_darwin_amd64.tar.gz
|
||||
```
|
||||
|
||||
```powershell tab="Windows PowerShell"
|
||||
# Compare this value to the one found in traefik-${traefik_version}_checksums.txt
|
||||
Get-FileHash ./traefik_${traefik_version}_windows_${arch}.zip -Algorithm SHA256
|
||||
```
|
||||
|
||||
??? tip "Extract the downloaded archive"
|
||||
|
||||
```bash tab="Linux"
|
||||
tar -zxvf traefik_${traefik_version}_linux_${arch}.tar.gz
|
||||
```
|
||||
|
||||
```bash tab="macOS"
|
||||
tar -zxvf ./traefik_${traefik_version}_darwin_amd64.tar.gz
|
||||
```
|
||||
|
||||
```powershell tab="Windows PowerShell"
|
||||
Expand-Archive traefik_${traefik_version}_windows_${arch}.zip
|
||||
```
|
||||
|
||||
And run it:
|
||||
|
||||
```bash
|
||||
./traefik --help
|
||||
```
|
||||
|
||||
## Compile your Binary from the Sources
|
||||
|
||||
All the details are available in the [Contributing Guide](../contributing/building-testing.md)
|
111
docs/content/getting-started/quick-start.md
Normal file
@ -0,0 +1,111 @@
|
||||
# Quick Start
|
||||
|
||||
A Simple Use Case Using Docker
|
||||
{: .subtitle }
|
||||
|
||||

|
||||
|
||||
## Launch Traefik With the Docker Provider
|
||||
|
||||
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
reverse-proxy:
|
||||
# The official v2.0 Traefik docker image
|
||||
image: traefik:v2.0
|
||||
# Enables the web UI and tells Traefik to listen to docker
|
||||
command: --api.insecure=true --providers.docker
|
||||
ports:
|
||||
# The HTTP port
|
||||
- "80:80"
|
||||
# The Web UI (enabled by --api.insecure=true)
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
# So that Traefik can listen to the Docker events
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
**That's it. Now you can launch Traefik!**
|
||||
|
||||
Start your `reverse-proxy` with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d reverse-proxy
|
||||
```
|
||||
|
||||
You can open a browser and go to [http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata) to see Traefik's API rawdata (we'll go back there once we have launched a service in step 2).
|
||||
|
||||
## Traefik Detects New Services and Creates the Route for You
|
||||
|
||||
Now that we have a Traefik instance up and running, we will deploy new services.
|
||||
|
||||
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
whoami:
|
||||
# A container that exposes an API to show its IP address
|
||||
image: containous/whoami
|
||||
labels:
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||
```
|
||||
|
||||
The above defines `whoami`: a simple web service that outputs information about the machine it is deployed on (its IP address, host, and so on).
|
||||
|
||||
Start the `whoami` service with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d whoami
|
||||
```
|
||||
|
||||
Go back to your browser ([http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata)) and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||
|
||||
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
||||
|
||||
```shell
|
||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||
```
|
||||
|
||||
_Shows the following output:_
|
||||
|
||||
```yaml
|
||||
Hostname: a656c8ddca6c
|
||||
IP: 172.27.0.3
|
||||
#...
|
||||
```
|
||||
|
||||
## More Instances? Traefik Load Balances Them
|
||||
|
||||
Run more instances of your `whoami` service with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d --scale whoami=2
|
||||
```
|
||||
|
||||
Go back to your browser ([http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata)) and see that Traefik has automatically detected the new instance of the container.
|
||||
|
||||
Finally, see that Traefik load-balances between the two instances of your service by running the following command twice:
|
||||
|
||||
```shell
|
||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||
```
|
||||
|
||||
The output will show alternatively one of the followings:
|
||||
|
||||
```yaml
|
||||
Hostname: a656c8ddca6c
|
||||
IP: 172.27.0.3
|
||||
#...
|
||||
```
|
||||
|
||||
```yaml
|
||||
Hostname: s458f154e1f1
|
||||
IP: 172.27.0.4
|
||||
# ...
|
||||
```
|
||||
|
||||
!!! question "Where to Go Next?"
|
||||
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it is time to dive into [the documentation](/) and let Traefik work for you!
|
22
docs/content/glossary.md
Normal file
@ -0,0 +1,22 @@
|
||||
# TODO -- Glossary
|
||||
|
||||
Where Every Technical Word finds its Definition`
|
||||
{: .subtitle}
|
||||
|
||||
- [ ] Provider
|
||||
- [ ] Types of providers (KV, annotation based, label based, configuration based)
|
||||
- [ ] Entrypoint
|
||||
- [ ] Routers
|
||||
- [ ] Middleware
|
||||
- [ ] Service
|
||||
- [ ] [Static configuration](getting-started/configuration-overview.md#the-static-configuration)
|
||||
- [ ] [Dynamic configuration](getting-started/configuration-overview.md#the-dynamic-configuration)
|
||||
- [ ] ACME
|
||||
- [ ] TraefikEE
|
||||
- [ ] Tracing
|
||||
- [ ] Metrics
|
||||
- [ ] Orchestrator
|
||||
- [ ] Key Value Store
|
||||
- [ ] Logs
|
||||
- [ ] Traefiker
|
||||
- [ ] Traefik (How to pronounce)
|
398
docs/content/https/acme.md
Normal file
@ -0,0 +1,398 @@
|
||||
# Let's Encrypt
|
||||
|
||||
Automatic HTTPS
|
||||
{: .subtitle }
|
||||
|
||||
You can configure Traefik to use an ACME provider (like Let's Encrypt) for automatic certificate generation.
|
||||
|
||||
!!! warning "Let's Encrypt and Rate Limiting"
|
||||
Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
??? example "Enabling ACME"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web-secure]
|
||||
address = ":443"
|
||||
|
||||
[certificatesResolvers.sample.acme]
|
||||
email = "your-email@your-domain.org"
|
||||
storage = "acme.json"
|
||||
[acme.httpChallenge]
|
||||
# used during the challenge
|
||||
entryPoint = "web"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
||||
web-secure:
|
||||
address: ":443"
|
||||
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
email: your-email@your-domain.org
|
||||
storage: acme.json
|
||||
httpChallenge:
|
||||
# used during the challenge
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=":80"
|
||||
--entryPoints.websecure.address=":443"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.email="your-email@your-domain.org"
|
||||
--certificatesResolvers.sample.acme.storage="acme.json"
|
||||
# used during the challenge
|
||||
--certificatesResolvers.sample.acme.httpChallenge.entryPoint=web
|
||||
```
|
||||
|
||||
??? note "Configuration Reference"
|
||||
|
||||
There are many available options for ACME.
|
||||
For a quick glance at what's possible, browse the configuration reference:
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
--8<-- "content/https/ref-acme.toml"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
--8<-- "content/https/ref-acme.yaml"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--8<-- "content/https/ref-acme.txt"
|
||||
```
|
||||
|
||||
## Automatic Renewals
|
||||
|
||||
Traefik automatically tracks the expiry date of ACME certificates it generates.
|
||||
|
||||
If there are less than 30 days remaining before the certificate expires, Traefik will attempt to renew it automatically.
|
||||
|
||||
!!! note
|
||||
Certificates that are no longer used may still be renewed, as Traefik does not currently check if the certificate is being used before renewing.
|
||||
|
||||
## The Different ACME Challenges
|
||||
|
||||
### `tlsChallenge`
|
||||
|
||||
Use the `TLS-ALPN-01` challenge to generate and renew ACME certificates by provisioning a TLS certificate.
|
||||
|
||||
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72),
|
||||
when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encrypt through port 443.
|
||||
|
||||
??? example "Configuring the `tlsChallenge`"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
[certificatesResolvers.sample.acme.tlsChallenge]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
tlsChallenge: {}
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.tlsChallenge=true
|
||||
```
|
||||
|
||||
### `httpChallenge`
|
||||
|
||||
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI.
|
||||
|
||||
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72),
|
||||
when using the `HTTP-01` challenge, `certificatesResolvers.sample.acme.httpChallenge.entryPoint` must be reachable by Let's Encrypt through port 80.
|
||||
|
||||
??? example "Using an EntryPoint Called http for the `httpChallenge`"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web-secure]
|
||||
address = ":443"
|
||||
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
[certificatesResolvers.sample.acme.httpChallenge]
|
||||
entryPoint = "web"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
||||
web-secure:
|
||||
address: ":443"
|
||||
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=":80"
|
||||
--entryPoints.websecure.address=":443"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.httpChallenge.entryPoint=web
|
||||
```
|
||||
|
||||
!!! note
|
||||
Redirection is fully compatible with the `HTTP-01` challenge.
|
||||
|
||||
### `dnsChallenge`
|
||||
|
||||
Use the `DNS-01` challenge to generate and renew ACME certificates by provisioning a DNS record.
|
||||
|
||||
??? example "Configuring a `dnsChallenge` with the DigitalOcean Provider"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
[certificatesResolvers.sample.acme.dnsChallenge]
|
||||
provider = "digitalocean"
|
||||
delayBeforeCheck = 0
|
||||
# ...
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
provider: digitalocean
|
||||
delayBeforeCheck: 0
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.provider=digitalocean
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.delayBeforeCheck=0
|
||||
# ...
|
||||
```
|
||||
|
||||
!!! important
|
||||
A `provider` is mandatory.
|
||||
|
||||
#### `providers`
|
||||
|
||||
Here is a list of supported `providers`, that can automate the DNS verification,
|
||||
along with the required environment variables and their [wildcard & root domain support](#wildcard-domains).
|
||||
Do not hesitate to complete it.
|
||||
|
||||
Every lego environment variable can be overridden by their respective `_FILE` counterpart, which should have a filepath to a file that contains the secret as its value.
|
||||
For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used to provide a Cloudflare API email address as a Docker secret named `traefik_cf-api-email`.
|
||||
|
||||
| Provider Name | Provider Code | Environment Variables | |
|
||||
|-------------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) |
|
||||
| [Auroradns](https://www.pcextreme.com/aurora/dns) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) |
|
||||
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | [Additional configuration](https://go-acme.github.io/lego/dns/azure) |
|
||||
| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) |
|
||||
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) |
|
||||
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
|
||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` - The `Global API Key` needs to be used, not the `Origin CA Key` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
|
||||
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
|
||||
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
|
||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
|
||||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
|
||||
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) |
|
||||
| [DNSPod](https://www.dnspod.com/) | `dnspod` | `DNSPOD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dnspod) |
|
||||
| [Domain Offensive (do.de)](https://www.do.de/) | `dode` | `DODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/dode) |
|
||||
| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dreamhost) |
|
||||
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/duckdns) |
|
||||
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/dyn) |
|
||||
| [EasyDNS](https://easydns.com/) | `easydns` | `EASYDNS_TOKEN`, `EASYDNS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/easydns) |
|
||||
| External Program | `exec` | `EXEC_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/exec) |
|
||||
| [Exoscale](https://www.exoscale.com) | `exoscale` | `EXOSCALE_API_KEY`, `EXOSCALE_API_SECRET`, `EXOSCALE_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/exoscale) |
|
||||
| [Fast DNS](https://www.akamai.com/) | `fastdns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/fastdns) |
|
||||
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandi) |
|
||||
| [Gandi v5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandiv5) |
|
||||
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) |
|
||||
| [GoDaddy](https://godaddy.com/) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) |
|
||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) |
|
||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
|
||||
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
|
||||
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) |
|
||||
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
|
||||
| [Joker.com](https://joker.com) | `joker` | `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
|
||||
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
|
||||
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
|
||||
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) |
|
||||
| manual | - | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
|
||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
|
||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
|
||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
|
||||
| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) |
|
||||
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) |
|
||||
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/nifcloud) |
|
||||
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) |
|
||||
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/otc) |
|
||||
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ovh) |
|
||||
| [Openstack Designate](https://docs.openstack.org/designate) | `designate` | `OS_AUTH_URL`, `OS_USERNAME`, `OS_PASSWORD`, `OS_TENANT_NAME`, `OS_REGION_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/designate) |
|
||||
| [Oracle Cloud](https://cloud.oracle.com/home) | `oraclecloud` | `OCI_COMPARTMENT_OCID`, `OCI_PRIVKEY_FILE`, `OCI_PRIVKEY_PASS`, `OCI_PUBKEY_FINGERPRINT`, `OCI_REGION`, `OCI_TENANCY_OCID`, `OCI_USER_OCID` | [Additional configuration](https://go-acme.github.io/lego/dns/oraclecloud) |
|
||||
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/pdns) |
|
||||
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rackspace) |
|
||||
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/rfc2136) |
|
||||
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | [Additional configuration](https://go-acme.github.io/lego/dns/route53) |
|
||||
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/sakuracloud) |
|
||||
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) |
|
||||
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/stackpath) |
|
||||
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) |
|
||||
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/vegadns) |
|
||||
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
|
||||
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) |
|
||||
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) |
|
||||
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) |
|
||||
|
||||
[^1]: more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
||||
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
|
||||
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
|
||||
[^4]: `docker stack` remark: there is no way to support terminal attached to container when deploying with `docker stack`, so you might need to run container with `docker run -it` to generate certificates using `manual` provider.
|
||||
|
||||
!!! note "`delayBeforeCheck`"
|
||||
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
||||
You can delay this operation by specifying a delay (in seconds) with `delayBeforeCheck` (value must be greater than zero).
|
||||
This option is useful when internal networks block external DNS queries.
|
||||
|
||||
#### `resolvers`
|
||||
|
||||
Use custom DNS servers to resolve the FQDN authority.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
[certificatesResolvers.sample.acme.dnsChallenge]
|
||||
# ...
|
||||
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
# ...
|
||||
resolvers:
|
||||
- "1.1.1.1:53"
|
||||
- "8.8.8.8:53"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.resolvers:="1.1.1.1:53,8.8.8.8:53"
|
||||
```
|
||||
|
||||
#### Wildcard Domains
|
||||
|
||||
[ACME V2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) supports wildcard certificates.
|
||||
As described in [Let's Encrypt's post](https://community.letsencrypt.org/t/staging-endpoint-for-acme-v2/49605) wildcard certificates can only be generated through a [`DNS-01` challenge](#dnschallenge).
|
||||
|
||||
## `caServer`
|
||||
|
||||
??? example "Using the Let's Encrypt staging server"
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
# ...
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.caServer="https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
# ...
|
||||
```
|
||||
|
||||
## `storage`
|
||||
|
||||
The `storage` option sets the location where your ACME certificates are saved to.
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.sample.acme]
|
||||
# ...
|
||||
storage = "acme.json"
|
||||
# ...
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
acme:
|
||||
# ...
|
||||
storage: acme.json
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.sample.acme.storage=acme.json
|
||||
# ...
|
||||
```
|
||||
|
||||
The value can refer to some kinds of storage:
|
||||
|
||||
- a JSON file
|
||||
|
||||
### In a File
|
||||
|
||||
ACME certificates can be stored in a JSON file that needs to have a `600` file mode .
|
||||
|
||||
In Docker you can mount either the JSON file, or the folder containing it:
|
||||
|
||||
```bash
|
||||
docker run -v "/my/host/acme.json:acme.json" traefik
|
||||
```
|
||||
|
||||
```bash
|
||||
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||
```
|
||||
|
||||
!!! warning
|
||||
For concurrency reason, this file cannot be shared across multiple instances of Traefik. Use a key value store entry instead.
|
||||
|
||||
## Fallback
|
||||
|
||||
If Let's Encrypt is not reachable, the following certificates will apply:
|
||||
|
||||
1. Previously generated ACME certificates (before downtime)
|
||||
1. Expired ACME certificates
|
||||
1. Provided certificates
|
||||
|
||||
!!! note
|
||||
For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted.
|
16
docs/content/https/overview.md
Normal file
@ -0,0 +1,16 @@
|
||||
# HTTPS & TLS
|
||||
|
||||
Overview
|
||||
{: .subtitle }
|
||||
|
||||
Traefik supports HTTPS & TLS, which concerns roughly two parts of the configuration:
|
||||
routers, and the TLS connection (and its underlying certificates).
|
||||
|
||||
When a router has to handle HTTPS traffic,
|
||||
it should be specified with a `tls` field of the router definition.
|
||||
See the TLS section of the [routers documentation](../routing/routers/index.md#tls).
|
||||
|
||||
The next sections of this documentation explain how to configure the TLS connection itself.
|
||||
That is to say, how to obtain [TLS certificates](./tls.md#certificates-definition):
|
||||
either through a definition in the dynamic configuration, or through [Let's Encrypt](./acme.md) (ACME).
|
||||
And how to configure [TLS options](./tls.md#tls-options), and [certificates stores](./tls.md#certificates-stores).
|
89
docs/content/https/ref-acme.toml
Normal file
@ -0,0 +1,89 @@
|
||||
# Enable ACME (Let's Encrypt): automatic SSL.
|
||||
[certificatesResolvers.sample.acme]
|
||||
|
||||
# Email address used for registration.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
email = "test@traefik.io"
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
storage = "acme.json"
|
||||
|
||||
# CA server to use.
|
||||
# Uncomment the line to use Let's Encrypt's staging server,
|
||||
# leave commented to go to prod.
|
||||
#
|
||||
# Optional
|
||||
# Default: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
#
|
||||
# caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
# KeyType to use.
|
||||
#
|
||||
# Optional
|
||||
# Default: "RSA4096"
|
||||
#
|
||||
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
|
||||
#
|
||||
# keyType = "RSA4096"
|
||||
|
||||
# Use a TLS-ALPN-01 ACME challenge.
|
||||
#
|
||||
# Optional (but recommended)
|
||||
#
|
||||
[certificatesResolvers.sample.acme.tlsChallenge]
|
||||
|
||||
# Use a HTTP-01 ACME challenge.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# [certificatesResolvers.sample.acme.httpChallenge]
|
||||
|
||||
# EntryPoint to use for the HTTP-01 challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
# entryPoint = "web"
|
||||
|
||||
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
|
||||
# Note: mandatory for wildcard certificate generation.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# [certificatesResolvers.sample.acme.dnsChallenge]
|
||||
|
||||
# DNS provider used.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
# provider = "digitalocean"
|
||||
|
||||
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
|
||||
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
|
||||
# Useful if internal networks block external DNS queries.
|
||||
#
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
# delayBeforeCheck = 0
|
||||
|
||||
# Use following DNS servers to resolve the FQDN authority.
|
||||
#
|
||||
# Optional
|
||||
# Default: empty
|
||||
#
|
||||
# resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||
|
||||
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
|
||||
#
|
||||
# NOT RECOMMENDED:
|
||||
# Increase the risk of reaching Let's Encrypt's rate limits.
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
# disablePropagationCheck = true
|
88
docs/content/https/ref-acme.txt
Normal file
@ -0,0 +1,88 @@
|
||||
# Enable ACME (Let's Encrypt): automatic SSL.
|
||||
|
||||
# Email address used for registration.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.sample.acme.email="test@traefik.io"
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.sample.acme.storage="acme.json"
|
||||
|
||||
# CA server to use.
|
||||
# Uncomment the line to use Let's Encrypt's staging server,
|
||||
# leave commented to go to prod.
|
||||
#
|
||||
# Optional
|
||||
# Default: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
#
|
||||
--certificatesResolvers.sample.acme.caServer="https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
# KeyType to use.
|
||||
#
|
||||
# Optional
|
||||
# Default: "RSA4096"
|
||||
#
|
||||
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
|
||||
#
|
||||
--certificatesResolvers.sample.acme.keyType=RSA4096
|
||||
|
||||
# Use a TLS-ALPN-01 ACME challenge.
|
||||
#
|
||||
# Optional (but recommended)
|
||||
#
|
||||
--certificatesResolvers.sample.acme.tlsChallenge=true
|
||||
|
||||
# Use a HTTP-01 ACME challenge.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.sample.acme.httpChallenge=true
|
||||
|
||||
# EntryPoint to use for the HTTP-01 challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.sample.acme.httpChallenge.entryPoint=web
|
||||
|
||||
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
|
||||
# Note: mandatory for wildcard certificate generation.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.sample.acme.dnsChallenge=true
|
||||
|
||||
# DNS provider used.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.provider=digitalocean
|
||||
|
||||
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
|
||||
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
|
||||
# Useful if internal networks block external DNS queries.
|
||||
#
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.delayBeforeCheck=0
|
||||
|
||||
# Use following DNS servers to resolve the FQDN authority.
|
||||
#
|
||||
# Optional
|
||||
# Default: empty
|
||||
#
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.resolvers="1.1.1.1:53,8.8.8.8:53"
|
||||
|
||||
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
|
||||
#
|
||||
# NOT RECOMMENDED:
|
||||
# Increase the risk of reaching Let's Encrypt's rate limits.
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
--certificatesResolvers.sample.acme.dnsChallenge.disablePropagationCheck=true
|
93
docs/content/https/ref-acme.yaml
Normal file
@ -0,0 +1,93 @@
|
||||
certificatesResolvers:
|
||||
sample:
|
||||
# Enable ACME (Let's Encrypt): automatic SSL.
|
||||
acme:
|
||||
|
||||
# Email address used for registration.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
email: "test@traefik.io"
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
storage: "acme.json"
|
||||
|
||||
# CA server to use.
|
||||
# Uncomment the line to use Let's Encrypt's staging server,
|
||||
# leave commented to go to prod.
|
||||
#
|
||||
# Optional
|
||||
# Default: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
#
|
||||
# caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
# KeyType to use.
|
||||
#
|
||||
# Optional
|
||||
# Default: "RSA4096"
|
||||
#
|
||||
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
|
||||
#
|
||||
# keyType: RSA4096
|
||||
|
||||
# Use a TLS-ALPN-01 ACME challenge.
|
||||
#
|
||||
# Optional (but recommended)
|
||||
#
|
||||
tlsChallenge:
|
||||
|
||||
# Use a HTTP-01 ACME challenge.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# httpChallenge:
|
||||
|
||||
# EntryPoint to use for the HTTP-01 challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
# entryPoint: web
|
||||
|
||||
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
|
||||
# Note: mandatory for wildcard certificate generation.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
# dnsChallenge:
|
||||
|
||||
# DNS provider used.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
# provider: digitalocean
|
||||
|
||||
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
|
||||
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
|
||||
# Useful if internal networks block external DNS queries.
|
||||
#
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
# delayBeforeCheck: 0
|
||||
|
||||
# Use following DNS servers to resolve the FQDN authority.
|
||||
#
|
||||
# Optional
|
||||
# Default: empty
|
||||
#
|
||||
# resolvers
|
||||
# - "1.1.1.1:53"
|
||||
# - "8.8.8.8:53"
|
||||
|
||||
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
|
||||
#
|
||||
# NOT RECOMMENDED:
|
||||
# Increase the risk of reaching Let's Encrypt's rate limits.
|
||||
#
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
# disablePropagationCheck: true
|
215
docs/content/https/tls.md
Normal file
@ -0,0 +1,215 @@
|
||||
# TLS
|
||||
|
||||
Transport Layer Security
|
||||
{: .subtitle }
|
||||
|
||||
## Certificates Definition
|
||||
|
||||
### Automated
|
||||
|
||||
See the [Let's Encrypt](./acme.md) page.
|
||||
|
||||
### User defined
|
||||
|
||||
To add / remove TLS certificates, even when Traefik is already running, their definition can be added to the [dynamic configuration](../getting-started/configuration-overview.md), in the `[[tls.certificates]]` section:
|
||||
|
||||
```toml tab="TOML"
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/other-domain.cert"
|
||||
keyFile = "/path/to/other-domain.key"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /path/to/domain.cert
|
||||
keyFile: /path/to/domain.key
|
||||
- certFile: /path/to/other-domain.cert
|
||||
keyFile: /path/to/other-domain.key
|
||||
```
|
||||
|
||||
!!! important "File Provider Only"
|
||||
|
||||
In the above example, we've used the [file provider](../providers/file.md) to handle these definitions.
|
||||
It is the only available method to configure the certificates (as well as the options and the stores).
|
||||
|
||||
## Certificates Stores
|
||||
|
||||
In Traefik, certificates are grouped together in certificates stores, which are defined as such:
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.stores]
|
||||
[tls.stores.default]
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
stores:
|
||||
default: {}
|
||||
```
|
||||
|
||||
!!! important "Restriction"
|
||||
|
||||
Any store definition other than the default one (named `default`) will be ignored,
|
||||
and there is thefore only one globally available TLS store.
|
||||
|
||||
In the `tls.certificates` section, a list of stores can then be specified to indicate where the certificates should be stored:
|
||||
|
||||
```toml tab="TOML"
|
||||
[[tls.certificates]]
|
||||
certFile = "/path/to/domain.cert"
|
||||
keyFile = "/path/to/domain.key"
|
||||
stores = ["default"]
|
||||
|
||||
[[tls.certificates]]
|
||||
# Note that since no store is defined,
|
||||
# the certificate below will be stored in the `default` store.
|
||||
certFile = "/path/to/other-domain.cert"
|
||||
keyFile = "/path/to/other-domain.key"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /path/to/domain.cert
|
||||
keyFile: /path/to/domain.key
|
||||
stores:
|
||||
- default
|
||||
# Note that since no store is defined,
|
||||
# the certificate below will be stored in the `default` store.
|
||||
- certFile: /path/to/other-domain.cert
|
||||
keyFile: /path/to/other-domain.key
|
||||
```
|
||||
|
||||
!!! important "Restriction"
|
||||
|
||||
The `stores` list will actually be ignored and automatically set to `["default"]`.
|
||||
|
||||
### Default Certificate
|
||||
|
||||
Traefik can use a default certificate for connections without a SNI, or without a matching domain.
|
||||
This default certificate should be defined in a TLS store:
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.stores]
|
||||
[tls.stores.default]
|
||||
[tls.stores.default.defaultCertificate]
|
||||
certFile = "path/to/cert.crt"
|
||||
keyFile = "path/to/cert.key"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: path/to/cert.crt
|
||||
keyFile: path/to/cert.key
|
||||
```
|
||||
|
||||
If no default certificate is provided, Traefik generates and uses a self-signed certificate.
|
||||
|
||||
## TLS Options
|
||||
|
||||
The TLS options allow one to configure some parameters of the TLS connection.
|
||||
|
||||
### Minimum TLS Version
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.options]
|
||||
|
||||
[tls.options.default]
|
||||
minVersion = "VersionTLS12"
|
||||
|
||||
[tls.options.mintls13]
|
||||
minVersion = "VersionTLS13"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
minVersion: VersionTLS12
|
||||
|
||||
mintls13:
|
||||
minVersion: VersionTLS13
|
||||
```
|
||||
|
||||
### Client Authentication (mTLS)
|
||||
|
||||
Traefik supports mutual authentication, through the `clientAuth` section.
|
||||
|
||||
For authentication policies that require verification of the client certificate, the certificate authority for the certificate should be set in `clientAuth.caFiles`.
|
||||
|
||||
The `clientAuth.clientAuthType` option governs the behaviour as follows:
|
||||
|
||||
- `NoClientCert`: disregards any client certificate.
|
||||
- `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided.
|
||||
- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles`.
|
||||
- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles`. Otherwise proceeds without any certificate.
|
||||
- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles`.
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
[tls.options.default.clientAuth]
|
||||
# in PEM format. each file can contain multiple CAs.
|
||||
caFiles = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||
clientAuthType = "RequireAndVerifyClientCert"
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
clientAuth:
|
||||
# in PEM format. each file can contain multiple CAs.
|
||||
caFiles:
|
||||
- tests/clientca1.crt
|
||||
- tests/clientca2.crt
|
||||
clientAuthType: RequireAndVerifyClientCert
|
||||
```
|
||||
|
||||
### Cipher Suites
|
||||
|
||||
See [cipherSuites](https://godoc.org/crypto/tls#pkg-constants) for more information.
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
```
|
||||
|
||||
### Strict SNI Checking
|
||||
|
||||
With strict SNI checking, Traefik won't allow connections from clients connections
|
||||
that do not specify a server_name extension.
|
||||
|
||||
```toml tab="TOML"
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
sniStrict = true
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
sniStrict: true
|
||||
```
|