mirror of
https://github.com/containous/traefik.git
synced 2025-03-14 00:58:23 +03:00
Compare commits
841 Commits
v2.10.0-rc
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
ae4a00b4bc | ||
|
30fe11eccf | ||
|
05eb438ae1 | ||
|
b7170df2c3 | ||
|
9e029a84c4 | ||
|
14e400bcd0 | ||
|
550d96ea67 | ||
|
3c99135bf9 | ||
|
474ab23fe9 | ||
|
c166a41c99 | ||
|
740b4cfd25 | ||
|
7cfd10db62 | ||
|
fa76ed57d3 | ||
|
9d8a42111f | ||
|
0dfd12ee61 | ||
|
07e6491ace | ||
|
32ea014d07 | ||
|
a3fd484728 | ||
|
9b0348577a | ||
|
efe03bc9da | ||
|
cce935493a | ||
|
f196de90e1 | ||
|
c2a294c872 | ||
|
8e5d4c6ae9 | ||
|
f0849e8ee6 | ||
|
1ccbf743cb | ||
|
1cfcf0d318 | ||
|
eb07a5ca1a | ||
|
56ea028e81 | ||
|
05c547f211 | ||
|
dcd9f2ea96 | ||
|
84e20aa9c3 | ||
|
b5a5e259ed | ||
|
8488214e93 | ||
|
b74767bfa4 | ||
|
786d9f3272 | ||
|
da2278b29a | ||
|
cfebed7328 | ||
|
4e441d09ed | ||
|
8f5dd7bd9d | ||
|
d04e2d717c | ||
|
cdd24e91b4 | ||
|
4fd6b10b7d | ||
|
86315e0f18 | ||
|
c20af070e3 | ||
|
8593581cbf | ||
|
857fbb933e | ||
|
8103992977 | ||
|
c5b92b5260 | ||
|
2afa03b55c | ||
|
2b6a04bc1d | ||
|
fb527dac1c | ||
|
ef887332c2 | ||
|
c19cf125e8 | ||
|
261e4395f3 | ||
|
435d28c790 | ||
|
4ce4bd7121 | ||
|
020ab5f347 | ||
|
ad7fb8e82b | ||
|
0528c054a6 | ||
|
ad99c5bbea | ||
|
8272be0eda | ||
|
0a6ff446c7 | ||
|
9a9644bafe | ||
|
95dd17e020 | ||
|
b0a72960bc | ||
|
a57e118a1a | ||
|
d2414feaff | ||
|
6aa56788ea | ||
|
1aa450c028 | ||
|
f9ff6049d3 | ||
|
d4d61151e1 | ||
|
456188fa0d | ||
|
03c170f264 | ||
|
7cb46626a1 | ||
|
5b53bae42d | ||
|
caf56e6aed | ||
|
69c8ecfa99 | ||
|
7db2bbb4a3 | ||
|
ee8305549a | ||
|
a31b026364 | ||
|
20d496268c | ||
|
6d3a685d5a | ||
|
845d0b5ac7 | ||
|
34aa3b75b8 | ||
|
f62fc67418 | ||
|
5f3c30e37b | ||
|
139f929ec8 | ||
|
e20409676a | ||
|
d152f7fafc | ||
|
ee449db656 | ||
|
38ac1e75a2 | ||
|
109a8712cc | ||
|
278e739242 | ||
|
db31a4c961 | ||
|
a1099bf8d0 | ||
|
596aadfe68 | ||
|
35ce6baaae | ||
|
95f20fc753 | ||
|
d9f58f94a2 | ||
|
a29628fa2e | ||
|
e280716645 | ||
|
f1c4ba2f26 | ||
|
a870c2af9b | ||
|
aa8eb1af6e | ||
|
189db8d990 | ||
|
68a8650297 | ||
|
1a5ea1c597 | ||
|
8983e45fcf | ||
|
ec214fa825 | ||
|
1c0094048b | ||
|
3a3ffab689 | ||
|
2302debac2 | ||
|
4974d9e4d7 | ||
|
33cf06b36a | ||
|
590ddfc990 | ||
|
39d7b77609 | ||
|
e85d02c530 | ||
|
74e0abf8bf | ||
|
d953ee69b4 | ||
|
26738cbf93 | ||
|
b1934231ca | ||
|
9588e51146 | ||
|
e87da0f390 | ||
|
8eb12795d7 | ||
|
cc14c165c0 | ||
|
f2ba4353b2 | ||
|
514914639a | ||
|
a4c0b1649d | ||
|
f547f1b22b | ||
|
42df9afeaf | ||
|
c8b0285c91 | ||
|
2df655cefe | ||
|
826a2b74aa | ||
|
47b4df71bf | ||
|
2b35c7e205 | ||
|
33c1d700c0 | ||
|
536e11d949 | ||
|
0ec12c7aa7 | ||
|
c120b70483 | ||
|
ab0713d587 | ||
|
090db6d4b0 | ||
|
5cfc11fe68 | ||
|
8a0c1e614f | ||
|
394f97bc48 | ||
|
8eadfbb990 | ||
|
ca5b70e196 | ||
|
cc80568d9e | ||
|
8ffd1854db | ||
|
6baa110adb | ||
|
5658c8ac06 | ||
|
1c80f12bc2 | ||
|
ef5f1b1508 | ||
|
fdce8c604a | ||
|
8c19652361 | ||
|
b7b4dd9554 | ||
|
e5c80637fc | ||
|
f437fb4230 | ||
|
9c50129520 | ||
|
00a5f4c401 | ||
|
a79cdd1dfa | ||
|
2096fd7081 | ||
|
ec00c4aa42 | ||
|
552bd8f180 | ||
|
f70949e3fa | ||
|
97caf758ef | ||
|
7f4ff359a2 | ||
|
47466a456e | ||
|
6f18344c56 | ||
|
e8ff825ed2 | ||
|
8527369797 | ||
|
7004f0e750 | ||
|
25caa72c09 | ||
|
8beba9f278 | ||
|
e90f4a7cb4 | ||
|
20cdbdbf31 | ||
|
08fe27ce5f | ||
|
0dc36379cf | ||
|
27948493aa | ||
|
e3ed52ba7c | ||
|
b22e081c7c | ||
|
62fa5f1a8e | ||
|
edc0a52b5a | ||
|
3d2336bc83 | ||
|
0605f8bf09 | ||
|
f18fcf3688 | ||
|
eeb99c3536 | ||
|
83871f27dd | ||
|
6e1f5dc071 | ||
|
ef5aa129c7 | ||
|
f54f28921b | ||
|
ef168b801c | ||
|
06e64af9e9 | ||
|
be156f6071 | ||
|
6f469ee1ec | ||
|
b46665c620 | ||
|
be13b5b55d | ||
|
e9d677f8cb | ||
|
7edb9a2101 | ||
|
4613ddd757 | ||
|
c441d04788 | ||
|
5d5dd9dd30 | ||
|
1508a2c221 | ||
|
934ca5fd22 | ||
|
f16d14cfa6 | ||
|
4625bdf5cb | ||
|
7b477f762a | ||
|
157cf75e38 | ||
|
ab35b3266a | ||
|
d339bfc8d2 | ||
|
7b08ecfa5e | ||
|
0a6b8780f0 | ||
|
45292148e7 | ||
|
fc563d3f6e | ||
|
a762cce430 | ||
|
306d3f277d | ||
|
6f7649fccc | ||
|
e8ab3af74d | ||
|
a7502c8700 | ||
|
54c3afd760 | ||
|
a2ab3e534d | ||
|
8cfa68a8e1 | ||
|
518caa79f9 | ||
|
373095f1a8 | ||
|
b641d5cf2a | ||
|
4d6cb6af03 | ||
|
9eb804a689 | ||
|
c02b72ca51 | ||
|
2bb712135d | ||
|
14e5d4b4b3 | ||
|
e485edbe9f | ||
|
d317cd90fc | ||
|
eccfcc0924 | ||
|
61bb3ab991 | ||
|
e62f8af23b | ||
|
a42d396ed2 | ||
|
7bb181dfa0 | ||
|
fbf6757ce9 | ||
|
f8a78b3b25 | ||
|
a6db1cac37 | ||
|
312ebb17ab | ||
|
a398536688 | ||
|
0be01cc067 | ||
|
f3eba8d3a2 | ||
|
7e75dc0819 | ||
|
b00f640d72 | ||
|
ac42dd8f83 | ||
|
4b5968e0cc | ||
|
42e1f2c9b1 | ||
|
bbeceba580 | ||
|
1ebd12ff82 | ||
|
89f3b272c3 | ||
|
093989fc14 | ||
|
06d7fab820 | ||
|
f90f9df1db | ||
|
9750bbc353 | ||
|
8c977b8f8c | ||
|
5841441005 | ||
|
0cf2032c15 | ||
|
d547b943df | ||
|
71d4b3b13c | ||
|
ac1dad3d14 | ||
|
be5c429825 | ||
|
e222d5cb2f | ||
|
9dc2155e63 | ||
|
c2cb4fac10 | ||
|
e8335a94a4 | ||
|
3d92f1645f | ||
|
3f74993f4a | ||
|
533c102d4f | ||
|
3eb7ecce19 | ||
|
0b34e0cdcb | ||
|
cf2869407d | ||
|
8ca27b4a1d | ||
|
6009aaed87 | ||
|
eb99c8c785 | ||
|
bf71560515 | ||
|
51f7f610c9 | ||
|
5ed972ccd8 | ||
|
2714831a4e | ||
|
6b3167d03e | ||
|
1417da4a21 | ||
|
3040f2659a | ||
|
6b1a584c2b | ||
|
3a80aa172c | ||
|
8dc9607db7 | ||
|
85f4fd0979 | ||
|
e56ae1a766 | ||
|
d2030a5835 | ||
|
58bbc0cf0f | ||
|
7056eeff6a | ||
|
ad613e58cd | ||
|
e7dc097901 | ||
|
12a37346a4 | ||
|
78079377e8 | ||
|
75881359ab | ||
|
0eb0a15aa1 | ||
|
8d9ff0c441 | ||
|
b611f967b7 | ||
|
4c4780f886 | ||
|
926a8e88e9 | ||
|
6b1adabeb5 | ||
|
4eedcabbb3 | ||
|
5bf4b536e2 | ||
|
5380e48747 | ||
|
ccc11a69f1 | ||
|
0f57f108ae | ||
|
c0b704e1b0 | ||
|
a50345bf8d | ||
|
bd93e224de | ||
|
ea019be133 | ||
|
02de683b94 | ||
|
930f84850b | ||
|
8970ae9199 | ||
|
de732ba53c | ||
|
0f7af2b4e7 | ||
|
e8324132f9 | ||
|
f52a36ba12 | ||
|
2ffa6c6feb | ||
|
210400905f | ||
|
ba6b4cbcc3 | ||
|
7dbd3f88f6 | ||
|
898eab20ac | ||
|
957a5f5e73 | ||
|
5a70910dce | ||
|
386c2ffb20 | ||
|
266a2d8b91 | ||
|
3ba53df005 | ||
|
5142733858 | ||
|
ecdfb10653 | ||
|
0f4e72d522 | ||
|
70dd7cdc71 | ||
|
c3e943658a | ||
|
4720caed04 | ||
|
c5a6b49330 | ||
|
a5df24a21d | ||
|
f5a811d8fa | ||
|
87db3300d3 | ||
|
4b4eaa49b5 | ||
|
fc174062b6 | ||
|
d700e95c21 | ||
|
aa760b5a71 | ||
|
a52c81fd91 | ||
|
127c0a7542 | ||
|
58dcbb43f9 | ||
|
f32884d9b8 | ||
|
173a18fdc1 | ||
|
876899be4b | ||
|
89108972b6 | ||
|
d42e75bb2e | ||
|
8d016f5e16 | ||
|
927f0bc01a | ||
|
900784a95a | ||
|
98c624bf1a | ||
|
f3479f532b | ||
|
8946dd1898 | ||
|
2a0cfda90b | ||
|
12fae2ebb8 | ||
|
9758b1ce36 | ||
|
fe4cca6e9c | ||
|
b1b4e6b918 | ||
|
8cb1829698 | ||
|
2f9905061e | ||
|
0a7a6afd59 | ||
|
b577b3a6ba | ||
|
230019eccf | ||
|
2090baa938 | ||
|
b7de043991 | ||
|
9e0800f938 | ||
|
e7d1a98c5e | ||
|
6f1bd54d86 | ||
|
983940ae60 | ||
|
6d8407893d | ||
|
a8a92eb2a5 | ||
|
2798e18e18 | ||
|
61defcdd66 | ||
|
ec638a741e | ||
|
097e71ad24 | ||
|
eabcb3e1c0 | ||
|
53a8bd76f2 | ||
|
0e89c48e38 | ||
|
385ff5055c | ||
|
b4f99ae3ac | ||
|
a696f7c654 | ||
|
3ca667a3d4 | ||
|
27af1fb478 | ||
|
e322184a98 | ||
|
69424a16a5 | ||
|
f9f22b7b70 | ||
|
b795f128d7 | ||
|
6706bb1612 | ||
|
3f48e6f8ef | ||
|
8ea339816a | ||
|
00b1d8b0bc | ||
|
21c6edcf58 | ||
|
5c48e3c96c | ||
|
c23c3e0ed3 | ||
|
b37aaea36d | ||
|
67f0700377 | ||
|
778dc22e14 | ||
|
cdf0c8b3ec | ||
|
359477c583 | ||
|
28d40e7f3c | ||
|
b368e71337 | ||
|
dc752c7847 | ||
|
6155c900be | ||
|
6ca4c5da5c | ||
|
7eac92f49c | ||
|
e6b1b05fdf | ||
|
b452f37e08 | ||
|
8cff718c53 | ||
|
bfda5e607f | ||
|
7fc56454ea | ||
|
c0a2e6b4b6 | ||
|
0f0cc420e1 | ||
|
9250b5937d | ||
|
e9bd2b45ac | ||
|
4406c337d4 | ||
|
ed10bc5833 | ||
|
e33bd6874f | ||
|
6e61fe0de1 | ||
|
05828bab07 | ||
|
0e215f9b61 | ||
|
7fdb1ff8af | ||
|
736f37cb58 | ||
|
cff71ee496 | ||
|
f02b223639 | ||
|
d4d23dce72 | ||
|
5e4dc783c7 | ||
|
440cb11250 | ||
|
42920595ad | ||
|
e68e647fd9 | ||
|
8b558646fc | ||
|
f8e45a0b29 | ||
|
d65de8fe6c | ||
|
5f2c00b438 | ||
|
c2c1c3e09e | ||
|
d8a778b5cd | ||
|
d8cf90dade | ||
|
6a06560318 | ||
|
a4aad5ce5c | ||
|
15973f5503 | ||
|
a4150409c8 | ||
|
aee515b930 | ||
|
05d2c86074 | ||
|
b0d19bd466 | ||
|
d99d2f95e6 | ||
|
8d2a2ff08f | ||
|
73e5dbbfe5 | ||
|
ee3e7cbbec | ||
|
9d8fd24730 | ||
|
f5d451d816 | ||
|
f84e00e481 | ||
|
fe0af1ec4b | ||
|
95312d5324 | ||
|
e3729ec600 | ||
|
20d6c19c30 | ||
|
7a7b03eb01 | ||
|
ea4f307fcd | ||
|
a6b00608d2 | ||
|
7b649e2f0c | ||
|
52e95deee3 | ||
|
70968bc6a9 | ||
|
da7bb5fc25 | ||
|
34bd611131 | ||
|
b9b7527762 | ||
|
240b83b773 | ||
|
584839e00b | ||
|
099c7e9444 | ||
|
83a5c5cfbd | ||
|
c1d9b9ee1f | ||
|
d53f5f01a0 | ||
|
4e11bf3c38 | ||
|
1a266c661a | ||
|
bda4f50eae | ||
|
19e6170fa5 | ||
|
0017471f0d | ||
|
76723b1288 | ||
|
cef842245c | ||
|
f69fd43122 | ||
|
e5062cef42 | ||
|
998c6174cd | ||
|
ac1753a614 | ||
|
d3516aec31 | ||
|
2c6418e17a | ||
|
1ffbffb26a | ||
|
fdf27eb644 | ||
|
945ff9b0f9 | ||
|
bbd5846c6a | ||
|
9f145dbc28 | ||
|
c84b510f0d | ||
|
2bc3fa7b4b | ||
|
fc897f6756 | ||
|
c31f5df854 | ||
|
b636b21167 | ||
|
167bdb0d53 | ||
|
7f29595c0a | ||
|
3fcf265d80 | ||
|
618fb5f232 | ||
|
d94e676083 | ||
|
141abce2d5 | ||
|
fc875b38e0 | ||
|
39fe3869b6 | ||
|
d582e01892 | ||
|
75790e0ab8 | ||
|
1391c35978 | ||
|
7bda07a422 | ||
|
9b6af61d1b | ||
|
5edac5eccd | ||
|
83e4abdb30 | ||
|
4e1e2f5ed0 | ||
|
c06629459d | ||
|
05be441027 | ||
|
6c9687f410 | ||
|
5cf1b95c29 | ||
|
74daa4cbb3 | ||
|
709ff6fb09 | ||
|
4fd5fca34f | ||
|
31a93d5045 | ||
|
4cb5825d11 | ||
|
15f50553e9 | ||
|
b4ca02da86 | ||
|
86be0a4e6f | ||
|
0e89a6bec7 | ||
|
c5808af4d9 | ||
|
c1ef742977 | ||
|
935d251b21 | ||
|
73769af0fe | ||
|
3b851a5ef2 | ||
|
deab4dae8e | ||
|
f7edb394f2 | ||
|
baf687218c | ||
|
153765f99f | ||
|
5a2e233a15 | ||
|
453e21c7c9 | ||
|
8b759ab797 | ||
|
88a2020817 | ||
|
c3545c620b | ||
|
1034646ae2 | ||
|
538f780a85 | ||
|
b931c8ae9b | ||
|
c5c61dbade | ||
|
1e7dbc70a0 | ||
|
6a2db4e4e9 | ||
|
1ea98d3d31 | ||
|
014fdfc4ec | ||
|
b5ec787fb6 | ||
|
0c8778639a | ||
|
8f29398573 | ||
|
676de5fb68 | ||
|
063f8fae79 | ||
|
efa6ca0fa1 | ||
|
4e831b920e | ||
|
bc84fdd006 | ||
|
d5cb9b50f4 | ||
|
e11ff98608 | ||
|
9df04df334 | ||
|
bb6cd581a6 | ||
|
8f9ad16f54 | ||
|
5d8b1949b7 | ||
|
d7ec0cedbf | ||
|
f1104ada65 | ||
|
3ba3ca6eb0 | ||
|
85039e0d54 | ||
|
9be523d772 | ||
|
8b77f0c2dd | ||
|
d02be003ab | ||
|
4d539273ad | ||
|
40de310927 | ||
|
18203f57d2 | ||
|
ef0e9c6f05 | ||
|
d37ea3e882 | ||
|
3174c69c66 | ||
|
f4f3dbe1f5 | ||
|
49f04f2772 | ||
|
03d2e35488 | ||
|
aece9a1051 | ||
|
547cd81599 | ||
|
b5251c6ac4 | ||
|
190b9b1afa | ||
|
9befe0dd51 | ||
|
683e2ee5c6 | ||
|
21da705ec9 | ||
|
a3ac456199 | ||
|
9843757834 | ||
|
f9831f5b1b | ||
|
177c4b0ed1 | ||
|
bab48bed22 | ||
|
6cb2ff2af9 | ||
|
5e0855ecc7 | ||
|
f57cee578f | ||
|
8da38ec0a5 | ||
|
a6d462f6e8 | ||
|
6c19a9cb8f | ||
|
0eeb85d01d | ||
|
64ff214ff8 | ||
|
111f3716fa | ||
|
4e0a05406b | ||
|
39b0aa6650 | ||
|
319517adef | ||
|
7a315bb043 | ||
|
34d2a816c2 | ||
|
81ce45271d | ||
|
3a461d2f23 | ||
|
980dac4572 | ||
|
ff7966f9cd | ||
|
e78374aa29 | ||
|
3bbc560283 | ||
|
ccf3a9995a | ||
|
e522446909 | ||
|
fea94a3393 | ||
|
4ddef9830b | ||
|
45bb00be04 | ||
|
cd8d5b8f10 | ||
|
eff294829f | ||
|
a69c1ba3b7 | ||
|
9adf0fb638 | ||
|
56e2110dc5 | ||
|
5be13802dc | ||
|
7345afd8b6 | ||
|
a84d5c0ef1 | ||
|
2a9471d278 | ||
|
0042562678 | ||
|
74ab88d47e | ||
|
6df9578ace | ||
|
cd7d324295 | ||
|
0e92b02474 | ||
|
9662cdca64 | ||
|
3dfaa3d5fa | ||
|
60123a8f3f | ||
|
2a7b2ef772 | ||
|
d51a2ce487 | ||
|
0a79643001 | ||
|
e77a66c2ac | ||
|
6858dbdd07 | ||
|
b2bb96390a | ||
|
e29a142f6a | ||
|
dae0491b61 | ||
|
f4ddf25e41 | ||
|
35c704ace3 | ||
|
789046f162 | ||
|
186e3e1541 | ||
|
088fe3c270 | ||
|
553ef94047 | ||
|
12e50e20e6 | ||
|
cd326654a7 | ||
|
3de29433f8 | ||
|
84516f962d | ||
|
f92b03a44d | ||
|
085b70c94e | ||
|
0e66ed87f8 | ||
|
d141e4a1ed | ||
|
679975beec | ||
|
8faed97e74 | ||
|
0b4c582088 | ||
|
c7cd0df3b3 | ||
|
286181aa61 | ||
|
6a34f238ce | ||
|
4b2c763cf3 | ||
|
d03d8d53fd | ||
|
8d0979bfd0 | ||
|
e95fde5652 | ||
|
ab7993428d | ||
|
b966215e6c | ||
|
b786f58f80 | ||
|
173154cf59 | ||
|
4acec60e72 | ||
|
c3880a69ca | ||
|
4d63eb30f9 | ||
|
0ee377bc9f | ||
|
dbc679dc30 | ||
|
fc7f732029 | ||
|
ba912e1a93 | ||
|
3216c8ab10 | ||
|
561c580701 | ||
|
3fd5c747a2 | ||
|
b6b6cef3da | ||
|
d651d1e7cf | ||
|
6f22b9e0a7 | ||
|
f29325c679 | ||
|
57780d8004 | ||
|
46f4a8541e | ||
|
1d85515aac | ||
|
55e00be36e | ||
|
d6457e6cbb | ||
|
ca2b9e8e77 | ||
|
d948784d38 | ||
|
1ddb0afb24 | ||
|
f518676238 | ||
|
db3e8a7f5a | ||
|
0bd367ebbd | ||
|
f4dc298406 | ||
|
4f6c15cc14 | ||
|
3f93e9ea71 | ||
|
eb585740a1 | ||
|
1709f3854c | ||
|
ebde81e91c | ||
|
47faae25d7 | ||
|
7792d197e6 | ||
|
deb4235028 | ||
|
7d66f439eb | ||
|
124ee3c48c | ||
|
bed6069e82 | ||
|
e29da5ad65 | ||
|
48de3b0230 | ||
|
00048a8351 | ||
|
2df5defd36 | ||
|
aaa763b7af | ||
|
8a68ece2cc | ||
|
08b80c20f0 | ||
|
d4daafa468 | ||
|
52d2d959af | ||
|
0a35fa096a | ||
|
a7ef965412 | ||
|
0a861716d4 | ||
|
4fbe9b81ec | ||
|
5fd6913ee5 | ||
|
7741c68eaa | ||
|
18077ff69a | ||
|
fa555d0d29 | ||
|
0e5898b2f8 | ||
|
aae76408e2 | ||
|
9cc9ed6a0c | ||
|
fecaec7a4a | ||
|
e62fe64ec9 | ||
|
6885e410f0 | ||
|
68ed875966 | ||
|
d1bdeb3a92 | ||
|
878e7de56a | ||
|
27353d0740 | ||
|
60bc47d00e | ||
|
606281a4a5 | ||
|
c5f23493ab | ||
|
db515195f0 | ||
|
9aa57f362b | ||
|
6977b68b72 | ||
|
8d8717d421 | ||
|
cf1cbb24df | ||
|
981ad74870 | ||
|
021f37ff71 | ||
|
511762cbf3 | ||
|
466d7461b7 | ||
|
1522afe2ec | ||
|
9c73c4c584 | ||
|
8f206ce319 | ||
|
65c59c9a09 | ||
|
e044e2b765 | ||
|
7805c683e3 | ||
|
e38c0c3969 | ||
|
619045eb4b | ||
|
2cebd0a083 | ||
|
c0e03ae17d | ||
|
9060522414 | ||
|
bb4eb32b1c | ||
|
30f991effa | ||
|
fc071a5ebe | ||
|
6082b22922 | ||
|
5635687a3e | ||
|
a3f1009170 | ||
|
79c5f34156 | ||
|
928db9bc42 | ||
|
c4bea197ab | ||
|
8174860770 | ||
|
598caf6f78 | ||
|
8b47c5adf7 | ||
|
a3bcf0f39e | ||
|
7875826bd9 | ||
|
7c2af10bbd | ||
|
598a257ae1 | ||
|
20e47d9102 | ||
|
f26e250648 | ||
|
80790cba17 | ||
|
241fb5093a | ||
|
044dc6a221 | ||
|
707f84e2e4 | ||
|
f94298e867 | ||
|
e1abf103c0 | ||
|
8cd4923e72 | ||
|
cd90b9761a | ||
|
f0f5f41fb9 | ||
|
8bf68b7efd | ||
|
b22aef7fff | ||
|
a2016a2953 | ||
|
c38d405cfd | ||
|
8c98234c07 | ||
|
d046af2e91 | ||
|
943238faba | ||
|
2b67f1f66f | ||
|
2ad1fd725a | ||
|
7129f03dc9 | ||
|
748254b6c5 | ||
|
a08a428787 | ||
|
3eeea2bb2b | ||
|
c2dac39da1 | ||
|
e54ee89330 | ||
|
fdd3f2abef | ||
|
517917cd7c | ||
|
6c75052a13 | ||
|
8cf9385938 | ||
|
519ed8bde5 | ||
|
46a61ce9c8 | ||
|
c57876c116 | ||
|
0d81fac3fc | ||
|
db287c4d31 | ||
|
4d86668af3 | ||
|
b93141992e | ||
|
a3e4c85ec0 | ||
|
bee86b5ac7 | ||
|
0ba51d62fa | ||
|
268d1edc8f | ||
|
580e7fa774 | ||
|
46c266661c | ||
|
61325d7b91 | ||
|
3f8aa13e68 | ||
|
08279047ae | ||
|
3dd4968c41 | ||
|
ba1ca68977 | ||
|
56f7515ecd | ||
|
27c02b5a56 | ||
|
630de7481e | ||
|
fadee5e87b | ||
|
67d9c8da0b | ||
|
1a1cfd1adc | ||
|
240fb871b6 | ||
|
d131ef57da | ||
|
281fa25844 | ||
|
bd3eaf4f5e | ||
|
7a6bfd3336 | ||
|
1b9873cae9 | ||
|
e86f21ae7b | ||
|
194247caae | ||
|
cd0654026a | ||
|
b39ce8cc58 | ||
|
33f0aed5ea | ||
|
188ef84c4f | ||
|
a5c520664a | ||
|
38d7011487 | ||
|
033fccccc7 | ||
|
df99a9fb57 | ||
|
d6b69e1347 | ||
|
4bd055cf97 |
@ -1,5 +1,5 @@
|
||||
dist/
|
||||
!dist/traefik
|
||||
!dist/**/traefik
|
||||
site/
|
||||
vendor/
|
||||
.idea/
|
||||
|
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: traefik
|
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -2,16 +2,16 @@
|
||||
PLEASE READ THIS MESSAGE.
|
||||
|
||||
Documentation fixes or enhancements:
|
||||
- for Traefik v1: use branch v1.7
|
||||
- for Traefik v2: use branch v2.10
|
||||
- for Traefik v2: use branch v2.11
|
||||
- for Traefik v3: use branch v3.3
|
||||
|
||||
Bug fixes:
|
||||
- for Traefik v1: use branch v1.7
|
||||
- for Traefik v2: use branch v2.10
|
||||
- for Traefik v2: use branch v2.11
|
||||
- for Traefik v3: use branch v3.3
|
||||
|
||||
Enhancements:
|
||||
- for Traefik v1: we only accept bug fixes
|
||||
- for Traefik v2: use branch master
|
||||
- for Traefik v2: we only accept bug fixes
|
||||
- for Traefik v3: use branch master
|
||||
|
||||
HOW TO WRITE A GOOD PULL REQUEST? https://doc.traefik.io/traefik/contributing/submitting-pull-requests/
|
||||
|
||||
|
90
.github/workflows/build.yaml
vendored
90
.github/workflows/build.yaml
vendored
@ -4,76 +4,78 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'script/gcg/**'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
GO_VERSION: '1.23'
|
||||
CGO_ENABLED: 0
|
||||
IN_DOCKER: ""
|
||||
|
||||
jobs:
|
||||
|
||||
build-webui:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build webui
|
||||
run: |
|
||||
make clean-webui generate-webui
|
||||
tar czvf webui.tar.gz ./webui/static/
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
path: webui.tar.gz
|
||||
uses: ./.github/workflows/template-webui.yaml
|
||||
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-20.04, macos-latest, windows-latest ]
|
||||
os: [ darwin, freebsd, linux, openbsd, windows ]
|
||||
arch: [ amd64, arm64 ]
|
||||
include:
|
||||
- os: freebsd
|
||||
arch: 386
|
||||
- os: linux
|
||||
arch: 386
|
||||
- os: linux
|
||||
arch: arm
|
||||
goarm: 6
|
||||
- os: linux
|
||||
arch: arm
|
||||
goarm: 7
|
||||
- os: linux
|
||||
arch: ppc64le
|
||||
- os: linux
|
||||
arch: riscv64
|
||||
- os: linux
|
||||
arch: s390x
|
||||
- os: openbsd
|
||||
arch: 386
|
||||
- os: windows
|
||||
arch: 386
|
||||
needs:
|
||||
- build-webui
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/traefik
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: go/src/github.com/traefik/traefik
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
env:
|
||||
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
'%LocalAppData%\go-build'
|
||||
key: ${{ runner.os }}-build-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-build-go-
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
path: ${{ github.workspace }}/go/src/github.com/traefik/traefik
|
||||
|
||||
- name: Untar webui
|
||||
run: tar xvf webui.tar.gz
|
||||
run: |
|
||||
tar xvf webui.tar.gz
|
||||
rm webui.tar.gz
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GOOS: ${{ matrix.os }}
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
run: make binary
|
||||
|
4
.github/workflows/check_doc.yml
vendored
4
.github/workflows/check_doc.yml
vendored
@ -9,11 +9,11 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: Check, verify and build documentation
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
70
.github/workflows/codeql.yml
vendored
Normal file
70
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- v*
|
||||
schedule:
|
||||
- cron: '11 22 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript', 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
if: ${{ matrix.language == 'go' }}
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
10
.github/workflows/documentation.yml
vendored
10
.github/workflows/documentation.yml
vendored
@ -7,24 +7,24 @@ on:
|
||||
- v*
|
||||
|
||||
env:
|
||||
STRUCTOR_VERSION: v1.13.1
|
||||
STRUCTOR_VERSION: v1.13.2
|
||||
MIXTUS_VERSION: v0.4.1
|
||||
|
||||
jobs:
|
||||
|
||||
docs:
|
||||
name: Doc Process
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'traefik/traefik'
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@ -47,6 +47,6 @@ jobs:
|
||||
run: $HOME/bin/seo -path=./site -product=traefik
|
||||
|
||||
- name: Publish documentation
|
||||
run: $HOME/bin/mixtus --dst-doc-path="./traefik" --dst-owner=traefik --dst-repo-name=doc --git-user-email="30906710+traefiker@users.noreply.github.com" --git-user-name=traefiker --src-doc-path="./site" --src-owner=containous --src-repo-name=traefik
|
||||
run: $HOME/bin/mixtus --dst-doc-path="./traefik" --dst-owner=traefik --dst-repo-name=doc --git-user-email="30906710+traefiker@users.noreply.github.com" --git-user-name=traefiker --src-doc-path="./site" --src-owner=traefik --src-repo-name=traefik
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
|
||||
|
53
.github/workflows/experimental.yaml
vendored
53
.github/workflows/experimental.yaml
vendored
@ -6,32 +6,65 @@ on:
|
||||
- master
|
||||
- v*
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
CGO_ENABLED: 0
|
||||
|
||||
jobs:
|
||||
|
||||
build-webui:
|
||||
if: github.repository == 'traefik/traefik'
|
||||
uses: ./.github/workflows/template-webui.yaml
|
||||
|
||||
experimental:
|
||||
if: github.repository == 'traefik/traefik'
|
||||
name: Build experimental image on branch
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
env:
|
||||
ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Build
|
||||
run: make generate binary
|
||||
|
||||
- name: Branch name
|
||||
run: echo ${GITHUB_REF##*/}
|
||||
|
||||
- name: Build docker experimental image
|
||||
run: docker build -t traefik/traefik:experimental-${GITHUB_REF##*/} -f exp.Dockerfile .
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Push to Docker Hub
|
||||
run: docker push traefik/traefik:experimental-${GITHUB_REF##*/}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
|
||||
- name: Untar webui
|
||||
run: |
|
||||
tar xvf webui.tar.gz
|
||||
rm webui.tar.gz
|
||||
|
||||
- name: Build docker experimental image
|
||||
env:
|
||||
DOCKER_BUILDX_ARGS: "--push"
|
||||
run: |
|
||||
make multi-arch-image-experimental-${GITHUB_REF##*/}
|
||||
|
138
.github/workflows/release.yaml
vendored
Normal file
138
.github/workflows/release.yaml
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
CGO_ENABLED: 0
|
||||
VERSION: ${{ github.ref_name }}
|
||||
TRAEFIKER_EMAIL: "traefiker@traefik.io"
|
||||
CODENAME: saintnectaire
|
||||
|
||||
jobs:
|
||||
|
||||
build-webui:
|
||||
if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
|
||||
uses: ./.github/workflows/template-webui.yaml
|
||||
|
||||
build:
|
||||
if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ linux-amd64, linux-386, linux-arm, linux-arm64, linux-ppc64le, linux-s390x, linux-riscv64, darwin, windows-amd64, windows-arm64, windows-386, freebsd, openbsd ]
|
||||
needs:
|
||||
- build-webui
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
env:
|
||||
# Ensure cache consistency on Linux, see https://github.com/actions/setup-go/pull/383
|
||||
ImageOS: ${{ matrix.os }}
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
|
||||
- name: Untar webui
|
||||
run: |
|
||||
tar xvf webui.tar.gz
|
||||
rm webui.tar.gz
|
||||
|
||||
- name: Go generate
|
||||
run: go generate
|
||||
|
||||
|
||||
- name: Generate goreleaser file
|
||||
run: |
|
||||
GORELEASER_CONFIG_FILE_PATH=$(go run ./internal/release "${{ matrix.os }}")
|
||||
echo "GORELEASER_CONFIG_FILE_PATH=$GORELEASER_CONFIG_FILE_PATH" >> $GITHUB_ENV
|
||||
|
||||
- name: Build with goreleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser
|
||||
# 'latest', 'nightly', or a semver
|
||||
version: '~> v2'
|
||||
args: release --clean --timeout="90m" --config "${{ env.GORELEASER_CONFIG_FILE_PATH }}"
|
||||
|
||||
- name: Artifact binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.os }}-binaries
|
||||
path: |
|
||||
dist/**/*_checksums.txt
|
||||
dist/**/*.tar.gz
|
||||
dist/**/*.zip
|
||||
retention-days: 1
|
||||
|
||||
release:
|
||||
if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs:
|
||||
- build
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
|
||||
- name: Untar webui
|
||||
run: |
|
||||
tar xvf webui.tar.gz
|
||||
rm webui.tar.gz
|
||||
|
||||
- name: Retrieve the secret and decode it to a file
|
||||
env:
|
||||
TRAEFIKER_RSA: ${{ secrets.TRAEFIKER_RSA }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${TRAEFIKER_RSA}" | base64 --decode > ~/.ssh/traefiker_rsa
|
||||
|
||||
- name: Download All Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist/
|
||||
pattern: "*-binaries"
|
||||
merge-multiple: true
|
||||
|
||||
- name: Publish Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
cat dist/**/*_checksums.txt >> "dist/traefik_${VERSION}_checksums.txt"
|
||||
rm dist/**/*_checksums.txt
|
||||
tar cfz "dist/traefik-${VERSION}.src.tar.gz" \
|
||||
--exclude-vcs \
|
||||
--exclude .idea \
|
||||
--exclude .travis \
|
||||
--exclude .semaphoreci \
|
||||
--exclude .github \
|
||||
--exclude dist .
|
||||
|
||||
chown -R "$(id -u)":"$(id -g)" dist/
|
||||
gh release create ${VERSION} ./dist/**/traefik*.{zip,tar.gz} ./dist/traefik*.{tar.gz,txt} --repo traefik/traefik --title ${VERSION} --notes ${VERSION}
|
||||
|
||||
./script/deploy.sh
|
||||
|
26
.github/workflows/sync-docker-images.yaml
vendored
Normal file
26
.github/workflows/sync-docker-images.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Sync Docker Images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Run every day
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
if: github.repository == 'traefik/traefik'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: imjasonh/setup-crane@v0.4
|
||||
|
||||
- name: Sync
|
||||
run: |
|
||||
EXCLUDED_TAGS="1.7.9-alpine v1.0.0-beta.392 v1.0.0-beta.404 v1.0.0-beta.704 v1.0.0-rc1 v1.7.9-alpine"
|
||||
EXCLUDED_REGEX=$(echo $EXCLUDED_TAGS | sed 's/ /|/g')
|
||||
diff <(crane ls traefik) <(crane ls ghcr.io/traefik/traefik) | grep '^<' | awk '{print $2}' | while read -r tag; do [[ "$tag" =~ ^($EXCLUDED_REGEX)$ ]] || (echo "Processing image: traefik:$tag"; crane cp "traefik:$tag" "ghcr.io/traefik/traefik:$tag"); done
|
||||
crane cp traefik:latest ghcr.io/traefik/traefik:latest
|
37
.github/workflows/template-webui.yaml
vendored
Normal file
37
.github/workflows/template-webui.yaml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
name: Build Web UI
|
||||
on:
|
||||
workflow_call: {}
|
||||
jobs:
|
||||
|
||||
build-webui:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: webui/.nvmrc
|
||||
cache: yarn
|
||||
cache-dependency-path: webui/yarn.lock
|
||||
|
||||
- name: Build webui
|
||||
working-directory: ./webui
|
||||
run: |
|
||||
yarn install
|
||||
yarn build
|
||||
|
||||
- name: Package webui
|
||||
run: |
|
||||
tar czvf webui.tar.gz ./webui/static/
|
||||
|
||||
- name: Artifact webui
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: webui.tar.gz
|
||||
path: webui.tar.gz
|
||||
retention-days: 1
|
39
.github/workflows/test-conformance.yaml
vendored
Normal file
39
.github/workflows/test-conformance.yaml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: Test K8s Gateway API conformance
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '.github/workflows/test-conformance.yaml'
|
||||
- 'pkg/provider/kubernetes/gateway/**'
|
||||
- 'integration/fixtures/k8s-conformance/**'
|
||||
- 'integration/k8s_conformance_test.go'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
CGO_ENABLED: 0
|
||||
|
||||
jobs:
|
||||
|
||||
test-conformance:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Avoid generating webui
|
||||
run: touch webui/static/index.html
|
||||
|
||||
- name: K8s Gateway API conformance test and report
|
||||
run: |
|
||||
make test-gateway-api-conformance
|
||||
git diff --exit-code
|
78
.github/workflows/test-integration.yaml
vendored
Normal file
78
.github/workflows/test-integration.yaml
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
name: Test Integration
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'script/gcg/**'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
CGO_ENABLED: 0
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Avoid generating webui
|
||||
run: touch webui/static/index.html
|
||||
|
||||
- name: Build binary
|
||||
run: make binary
|
||||
|
||||
test-integration:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
parallel: [12]
|
||||
index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Avoid generating webui
|
||||
run: touch webui/static/index.html
|
||||
|
||||
- name: Build binary
|
||||
run: make binary
|
||||
|
||||
- name: Generate go test Slice
|
||||
id: test_split
|
||||
uses: hashicorp-forge/go-test-split-action@v2.0.0
|
||||
with:
|
||||
packages: ./integration
|
||||
total: ${{ matrix.parallel }}
|
||||
index: ${{ matrix.index }}
|
||||
|
||||
- name: Run Integration tests
|
||||
run: |
|
||||
TESTS=$(echo "${{ steps.test_split.outputs.run}}" | sed 's/\$/\$\$/g')
|
||||
TESTFLAGS="-run \"${TESTS}\"" make test-integration
|
53
.github/workflows/test-unit.yaml
vendored
53
.github/workflows/test-unit.yaml
vendored
@ -4,43 +4,54 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'script/gcg/**'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
IN_DOCKER: ""
|
||||
GO_VERSION: '1.23'
|
||||
|
||||
jobs:
|
||||
|
||||
test-unit:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/traefik
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: go/src/github.com/traefik/traefik
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: ${{ runner.os }}-test-unit-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-test-unit-go-
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Avoid generating webui
|
||||
run: touch webui/static/index.html
|
||||
|
||||
- name: Tests
|
||||
run: make test-unit
|
||||
|
||||
test-ui-unit:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: webui/.nvmrc
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: webui/yarn.lock
|
||||
|
||||
- name: UI unit tests
|
||||
run: |
|
||||
yarn --cwd webui install
|
||||
yarn --cwd webui test:unit:ci
|
||||
|
88
.github/workflows/validate.yaml
vendored
88
.github/workflows/validate.yaml
vendored
@ -6,84 +6,74 @@ on:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
GOLANGCI_LINT_VERSION: v1.52.2
|
||||
MISSSPELL_VERSION: v0.4.0
|
||||
IN_DOCKER: ""
|
||||
GO_VERSION: '1.23'
|
||||
GOLANGCI_LINT_VERSION: v1.64.2
|
||||
MISSPELL_VERSION: v0.6.0
|
||||
|
||||
jobs:
|
||||
|
||||
validate:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/traefik
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: go/src/github.com/traefik/traefik
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: ${{ runner.os }}-validate-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-validate-go-
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
|
||||
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: "${{ env.GOLANGCI_LINT_VERSION }}"
|
||||
|
||||
- name: Install missspell ${{ env.MISSSPELL_VERSION }}
|
||||
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSSPELL_VERSION}
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: Install misspell ${{ env.MISSPELL_VERSION }}
|
||||
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
|
||||
|
||||
- name: Avoid generating webui
|
||||
run: touch webui/static/index.html
|
||||
|
||||
- name: Validate
|
||||
run: make validate
|
||||
run: make validate-files
|
||||
|
||||
validate-generate:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/traefik
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: go/src/github.com/traefik/traefik
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: ${{ runner.os }}-validate-generate-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-validate-generate-go-
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
|
||||
- name: go generate
|
||||
run: |
|
||||
go generate
|
||||
make generate
|
||||
git diff --exit-code
|
||||
|
||||
- name: go mod tidy
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@ plugins-storage/
|
||||
plugins-local/
|
||||
traefik_changelog.md
|
||||
integration/tailscale.secret
|
||||
integration/conformance-reports/**/experimental-dev-default-report.yaml
|
||||
|
130
.golangci.yml
130
.golangci.yml
@ -1,8 +1,6 @@
|
||||
run:
|
||||
timeout: 10m
|
||||
skip-files: []
|
||||
skip-dirs:
|
||||
- pkg/provider/kubernetes/crd/generated/
|
||||
relative-path-mode: cfg
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
@ -26,10 +24,17 @@ linters-settings:
|
||||
- ^spew\.Print(f|ln)?$
|
||||
- ^spew\.Dump$
|
||||
depguard:
|
||||
list-type: denylist
|
||||
include-go-root: false
|
||||
packages:
|
||||
- github.com/pkg/errors
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- pkg: "github.com/instana/testify"
|
||||
desc: not allowed
|
||||
- pkg: "github.com/pkg/errors"
|
||||
desc: Should be replaced by standard lib errors package
|
||||
- pkg: "k8s.io/api/networking/v1beta1"
|
||||
desc: This API is deprecated
|
||||
- pkg: "k8s.io/api/extensions/v1beta1"
|
||||
desc: This API is deprecated
|
||||
godox:
|
||||
keywords:
|
||||
- FIXME
|
||||
@ -44,14 +49,10 @@ linters-settings:
|
||||
pkg: "k8s.io/api/core/v1"
|
||||
- alias: netv1
|
||||
pkg: "k8s.io/api/networking/v1"
|
||||
- alias: netv1beta1
|
||||
pkg: "k8s.io/api/networking/v1beta1"
|
||||
- alias: admv1
|
||||
pkg: "k8s.io/api/admission/v1"
|
||||
- alias: admv1beta1
|
||||
pkg: "k8s.io/api/admission/v1beta1"
|
||||
- alias: extv1beta1
|
||||
pkg: "k8s.io/api/extensions/v1beta1"
|
||||
- alias: metav1
|
||||
pkg: "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
- alias: ktypes
|
||||
@ -84,18 +85,16 @@ linters-settings:
|
||||
pkg: "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
||||
|
||||
# Traefik Kubernetes rewrites:
|
||||
- alias: containousv1alpha1
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefikcontainous/v1alpha1"
|
||||
- alias: traefikv1alpha1
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
||||
pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
||||
- alias: traefikclientset
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
- alias: traefikinformers
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/generated/informers/externalversions"
|
||||
pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/informers/externalversions"
|
||||
- alias: traefikscheme
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
- alias: traefikcrdfake
|
||||
pkg: "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake"
|
||||
pkg: "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake"
|
||||
tagalign:
|
||||
align: false
|
||||
sort: true
|
||||
@ -141,31 +140,35 @@ linters-settings:
|
||||
- name: unreachable-code
|
||||
- name: redefines-builtin-id
|
||||
gomoddirectives:
|
||||
tool-forbidden: true
|
||||
toolchain-pattern: 'go1\.\d+\.\d+$'
|
||||
go-version-pattern: '^1\.\d+(\.0)?$'
|
||||
replace-allow-list:
|
||||
- github.com/abbot/go-http-auth
|
||||
- github.com/go-check/check
|
||||
- github.com/gorilla/mux
|
||||
- github.com/mailgun/minheap
|
||||
- github.com/mailgun/multibuf
|
||||
- github.com/jaguilar/vt100
|
||||
|
||||
- github.com/cucumber/godog
|
||||
- github.com/http-wasm/http-wasm-host-go
|
||||
testifylint:
|
||||
disable:
|
||||
- suite-dont-use-pkg
|
||||
- require-error
|
||||
- go-require
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- -SA1019
|
||||
errcheck:
|
||||
exclude-functions:
|
||||
- fmt.Fprintln
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- deadcode # deprecated
|
||||
- exhaustivestruct # deprecated
|
||||
- golint # deprecated
|
||||
- ifshort # deprecated
|
||||
- interfacer # deprecated
|
||||
- maligned # deprecated
|
||||
- nosnakecase # deprecated
|
||||
- scopelint # deprecated
|
||||
- scopelint # deprecated
|
||||
- structcheck # deprecated
|
||||
- varcheck # deprecated
|
||||
- tenv # Deprecated
|
||||
- sqlclosecheck # not relevant (SQL)
|
||||
- rowserrcheck # not relevant (SQL)
|
||||
- execinquery # not relevant (SQL)
|
||||
- cyclop # duplicate of gocyclo
|
||||
- lll # Not relevant
|
||||
- gocyclo # FIXME must be fixed
|
||||
@ -179,14 +182,14 @@ linters:
|
||||
- gochecknoglobals
|
||||
- wsl # Too strict
|
||||
- nlreturn # Not relevant
|
||||
- gomnd # Too strict
|
||||
- mnd # Too strict
|
||||
- stylecheck # skip because report issues related to some generated files.
|
||||
- testpackage # Too strict
|
||||
- tparallel # Not relevant
|
||||
- paralleltest # Not relevant
|
||||
- exhaustive # Not relevant
|
||||
- exhaustruct # Not relevant
|
||||
- goerr113 # Too strict
|
||||
- err113 # Too strict
|
||||
- wrapcheck # Too strict
|
||||
- noctx # Too strict
|
||||
- bodyclose # too many false-positive
|
||||
@ -199,29 +202,27 @@ linters:
|
||||
- containedctx # too many false-positive
|
||||
- maintidx # kind of duplicate of gocyclo
|
||||
- nonamedreturns # Too strict
|
||||
- gosmopolitan # not relevant
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
max-per-linter: 0
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
exclude-dirs:
|
||||
- pkg/provider/kubernetes/crd/generated/
|
||||
exclude:
|
||||
- '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"
|
||||
- 'SA1019: http.CloseNotifier has been deprecated' # FIXME must be fixed
|
||||
- 'SA1019: cfg.SSLRedirect is deprecated'
|
||||
- 'SA1019: cfg.SSLTemporaryRedirect is deprecated'
|
||||
- 'SA1019: cfg.SSLHost is deprecated'
|
||||
- 'SA1019: cfg.SSLForceHost is deprecated'
|
||||
- 'SA1019: cfg.FeaturePolicy is deprecated'
|
||||
- 'SA1019: c.Providers.ConsulCatalog.Namespace is deprecated'
|
||||
- 'SA1019: c.Providers.Consul.Namespace is deprecated'
|
||||
- 'SA1019: c.Providers.Nomad.Namespace is deprecated'
|
||||
- 'fmt.Sprintf can be replaced with string'
|
||||
- 'SA1019: dockertypes.ContainerNode is deprecated'
|
||||
exclude-rules:
|
||||
- path: '(.+)_test.go'
|
||||
linters:
|
||||
- goconst
|
||||
- funlen
|
||||
- godot
|
||||
- canonicalheader
|
||||
- fatcontext
|
||||
- path: '(.+)_test.go'
|
||||
text: ' always receives '
|
||||
linters:
|
||||
@ -230,13 +231,13 @@ issues:
|
||||
text: 'struct-tag: unknown option ''inline'' in JSON tag'
|
||||
linters:
|
||||
- revive
|
||||
- path: pkg/server/service/bufferpool.go
|
||||
- path: pkg/proxy/httputil/bufferpool.go
|
||||
text: 'SA6002: argument should be pointer-like to avoid allocations'
|
||||
- path: pkg/server/middleware/middlewares.go
|
||||
text: "Function 'buildConstructor' has too many statements"
|
||||
linters:
|
||||
- funlen
|
||||
- path: pkg/tracing/haystack/logger.go
|
||||
- path: pkg/logs/haystack.go
|
||||
linters:
|
||||
- goprintffuncname
|
||||
- path: pkg/tracing/tracing.go
|
||||
@ -247,6 +248,12 @@ issues:
|
||||
text: 'SA1019: config.ClientCAs.Subjects has been deprecated since Go 1.18'
|
||||
- path: pkg/types/tls_test.go
|
||||
text: 'SA1019: tlsConfig.RootCAs.Subjects has been deprecated since Go 1.18'
|
||||
- path: pkg/provider/kubernetes/crd/kubernetes.go
|
||||
text: 'SA1019: middleware.Spec.IPWhiteList is deprecated: please use IPAllowList instead.'
|
||||
- path: pkg/server/middleware/tcp/middlewares.go
|
||||
text: 'SA1019: config.IPWhiteList is deprecated: please use IPAllowList instead.'
|
||||
- path: pkg/server/middleware/middlewares.go
|
||||
text: 'SA1019: config.IPWhiteList is deprecated: please use IPAllowList instead.'
|
||||
- path: pkg/provider/kubernetes/(crd|gateway)/client.go
|
||||
linters:
|
||||
- interfacebloat
|
||||
@ -261,7 +268,38 @@ issues:
|
||||
text: 'Duplicate words \(sub\) found'
|
||||
linters:
|
||||
- dupword
|
||||
- path: pkg/provider/kubernetes/crd/kubernetes.go
|
||||
text: "Function 'loadConfigurationFromCRD' has too many statements"
|
||||
linters:
|
||||
- funlen
|
||||
- path: pkg/provider/kubernetes/gateway/client_mock_test.go
|
||||
text: 'unusedwrite: unused write to field'
|
||||
linters:
|
||||
- govet
|
||||
- path: pkg/cli/deprecation.go
|
||||
linters:
|
||||
- goconst
|
||||
- path: pkg/cli/loader_file.go
|
||||
linters:
|
||||
- goconst
|
||||
- path: pkg/provider/acme/local_store.go
|
||||
linters:
|
||||
- musttag
|
||||
- path: pkg/types/metrics.go
|
||||
linters:
|
||||
- goconst
|
||||
- path: pkg/tls/certificate.go
|
||||
text: 'the methods of "Certificates" use pointer receiver and non-pointer receiver.'
|
||||
linters:
|
||||
- recvcheck
|
||||
- path: pkg/plugins/middlewarewasm.go
|
||||
text: 'the methods of "wasmMiddlewareBuilder" use pointer receiver and non-pointer receiver.'
|
||||
linters:
|
||||
- recvcheck
|
||||
|
||||
output:
|
||||
show-stats: true
|
||||
sort-results: true
|
||||
sort-order:
|
||||
- linter
|
||||
- file
|
||||
|
@ -1,8 +1,11 @@
|
||||
project_name: traefik
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go generate
|
||||
[[if .GOARCH]]
|
||||
dist: "./dist/[[ .GOOS ]]-[[ .GOARCH ]]"
|
||||
[[else]]
|
||||
dist: "./dist/[[ .GOOS ]]"
|
||||
[[end]]
|
||||
|
||||
builds:
|
||||
- binary: traefik
|
||||
@ -11,22 +14,23 @@ builds:
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- -s -w -X github.com/traefik/traefik/v2/pkg/version.Version={{.Version}} -X github.com/traefik/traefik/v2/pkg/version.Codename={{.Env.CODENAME}} -X github.com/traefik/traefik/v2/pkg/version.BuildDate={{.Date}}
|
||||
- -s -w -X github.com/traefik/traefik/v3/pkg/version.Version={{.Version}} -X github.com/traefik/traefik/v3/pkg/version.Codename={{.Env.CODENAME}} -X github.com/traefik/traefik/v3/pkg/version.BuildDate={{.Date}}
|
||||
flags:
|
||||
- -trimpath
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
- freebsd
|
||||
- openbsd
|
||||
- "[[ .GOOS ]]"
|
||||
goarch:
|
||||
[[if .GOARCH]]
|
||||
- "[[ .GOARCH ]]"
|
||||
[[else]]
|
||||
- amd64
|
||||
- '386'
|
||||
- arm
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
- riscv64
|
||||
[[end]]
|
||||
goarm:
|
||||
- '7'
|
||||
- '6'
|
||||
@ -45,7 +49,7 @@ builds:
|
||||
goarch: arm
|
||||
|
||||
changelog:
|
||||
skip: true
|
||||
disable: true
|
||||
|
||||
archives:
|
||||
- id: traefik
|
@ -1,83 +1,13 @@
|
||||
version: v1.0
|
||||
name: Traefik
|
||||
name: Traefik Release - deprecated
|
||||
agent:
|
||||
machine:
|
||||
type: e1-standard-4
|
||||
os_image: ubuntu1804
|
||||
|
||||
fail_fast:
|
||||
stop:
|
||||
when: "branch != 'master'"
|
||||
|
||||
auto_cancel:
|
||||
queued:
|
||||
when: "branch != 'master'"
|
||||
running:
|
||||
when: "branch != 'master'"
|
||||
|
||||
global_job_config:
|
||||
prologue:
|
||||
commands:
|
||||
- curl -sSfL https://raw.githubusercontent.com/ldez/semgo/master/godownloader.sh | sudo sh -s -- -b "/usr/local/bin"
|
||||
- sudo semgo go1.20
|
||||
- export "GOPATH=$(go env GOPATH)"
|
||||
- export "SEMAPHORE_GIT_DIR=${GOPATH}/src/github.com/traefik/${SEMAPHORE_PROJECT_NAME}"
|
||||
- export "PATH=${GOPATH}/bin:${PATH}"
|
||||
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
|
||||
- export GOPROXY=https://proxy.golang.org,direct
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.52.2
|
||||
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
|
||||
- checkout
|
||||
- cache restore traefik-$(checksum go.sum)
|
||||
|
||||
type: f1-standard-2
|
||||
os_image: ubuntu2204
|
||||
blocks:
|
||||
- name: Test Integration
|
||||
dependencies: []
|
||||
run:
|
||||
when: "branch =~ '.*' OR pull_request =~'.*'"
|
||||
- name: 'Do nothing'
|
||||
task:
|
||||
jobs:
|
||||
- name: Test Integration
|
||||
- name: 'Do nothing'
|
||||
commands:
|
||||
- make pull-images
|
||||
- touch webui/static/index.html # Avoid generating webui
|
||||
- IN_DOCKER="" make binary
|
||||
- make test-integration
|
||||
- df -h
|
||||
epilogue:
|
||||
always:
|
||||
commands:
|
||||
- cache store traefik-$(checksum go.sum) $HOME/go/pkg/mod
|
||||
|
||||
- name: Release
|
||||
dependencies: []
|
||||
run:
|
||||
when: "tag =~ '.*'"
|
||||
task:
|
||||
agent:
|
||||
machine:
|
||||
type: e1-standard-8
|
||||
os_image: ubuntu1804
|
||||
secrets:
|
||||
- name: traefik
|
||||
env_vars:
|
||||
- name: GH_VERSION
|
||||
value: 1.12.1
|
||||
- name: CODENAME
|
||||
value: "saintmarcelin"
|
||||
- name: IN_DOCKER
|
||||
value: ""
|
||||
prologue:
|
||||
commands:
|
||||
- export VERSION=${SEMAPHORE_GIT_TAG_NAME}
|
||||
- curl -sSL -o /tmp/gh_${GH_VERSION}_linux_amd64.tar.gz https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz
|
||||
- tar -zxvf /tmp/gh_${GH_VERSION}_linux_amd64.tar.gz -C /tmp
|
||||
- sudo mv /tmp/gh_${GH_VERSION}_linux_amd64/bin/gh /usr/local/bin/gh
|
||||
- sudo rm -rf ~/.phpbrew ~/.kerl ~/.sbt ~/.nvm ~/.npm ~/.kiex /usr/lib/jvm /opt/az /opt/firefox # Remove unnecessary data.
|
||||
- sudo service docker stop && sudo umount /var/lib/docker && sudo service docker start # Unmounts the docker disk and the whole system disk is usable.
|
||||
jobs:
|
||||
- name: Release
|
||||
commands:
|
||||
- make release-packages
|
||||
- gh release create ${SEMAPHORE_GIT_TAG_NAME} ./dist/traefik*.* --repo traefik/traefik --title ${SEMAPHORE_GIT_TAG_NAME} --notes ${SEMAPHORE_GIT_TAG_NAME}
|
||||
- ./script/deploy.sh
|
||||
- echo "Do nothing"
|
||||
|
1464
CHANGELOG.md
1464
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,18 @@ 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.
|
||||
|
||||
When an inappropriate behavior is reported, maintainers will discuss on the Maintainer's Discord before marking the message as "abuse".
|
||||
This conversation beforehand avoids one-sided decisions.
|
||||
|
||||
The first message will be edited and marked as abuse.
|
||||
The second edited message and marked as abuse results in a 7-day ban.
|
||||
The third edited message and marked as abuse results in a permanent ban.
|
||||
|
||||
The content of edited messages is:
|
||||
`Dear user, we want traefik to provide a welcoming and respectful environment. Your [comment/issue/PR] has been reported and marked as abuse according to our [Code of Conduct](./CODE_OF_CONDUCT.md). Thank you.`
|
||||
|
||||
The [report must be resolved](https://docs.github.com/en/communities/moderating-comments-and-conversations/managing-reported-content-in-your-organizations-repository#resolving-a-report) accordingly.
|
||||
|
||||
## 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]
|
||||
|
12
Dockerfile
12
Dockerfile
@ -1,6 +1,12 @@
|
||||
FROM scratch
|
||||
COPY script/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY dist/traefik /
|
||||
# syntax=docker/dockerfile:1.2
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk add --no-cache --no-progress ca-certificates tzdata
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
COPY ./dist/$TARGETPLATFORM/traefik /
|
||||
|
||||
EXPOSE 80
|
||||
VOLUME ["/tmp"]
|
||||
|
||||
ENTRYPOINT ["/traefik"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2020 Containous SAS; 2020-2023 Traefik Labs
|
||||
Copyright (c) 2016-2020 Containous SAS; 2020-2025 Traefik Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
236
Makefile
236
Makefile
@ -1,126 +1,117 @@
|
||||
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/')
|
||||
|
||||
TAG_NAME := $(shell git tag -l --contains HEAD)
|
||||
TAG_NAME := $(shell git describe --abbrev=0 --tags --exact-match)
|
||||
SHA := $(shell git rev-parse HEAD)
|
||||
VERSION_GIT := $(if $(TAG_NAME),$(TAG_NAME),$(SHA))
|
||||
VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT))
|
||||
|
||||
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)))
|
||||
BIN_NAME := traefik
|
||||
CODENAME ?= cheddar
|
||||
|
||||
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"traefik/traefik")
|
||||
DATE := $(shell date -u '+%Y-%m-%d_%I:%M:%S%p')
|
||||
|
||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)",-v "/var/run/docker.sock:/var/run/docker.sock")
|
||||
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
|
||||
# Default build target
|
||||
GOOS := $(shell go env GOOS)
|
||||
GOARCH := $(shell go env GOARCH)
|
||||
|
||||
# only used when running in docker
|
||||
TRAEFIK_ENVS := \
|
||||
-e OS_ARCH_ARG \
|
||||
-e OS_PLATFORM_ARG \
|
||||
-e TESTFLAGS \
|
||||
-e VERBOSE \
|
||||
-e VERSION \
|
||||
-e CODENAME \
|
||||
-e TESTDIRS \
|
||||
-e CI \
|
||||
-e IN_DOCKER=true # Indicator for integration tests that we are running inside a container.
|
||||
LINT_EXECUTABLES = misspell shellcheck
|
||||
|
||||
TRAEFIK_MOUNT := -v "$(CURDIR)/dist:/go/src/github.com/traefik/traefik/dist"
|
||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
DOCKER_NON_INTERACTIVE ?= false
|
||||
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_TEST := docker run --add-host=host.docker.internal:127.0.0.1 --rm --name=traefik --network traefik-test-network -v $(PWD):$(PWD) -w $(PWD) $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
|
||||
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -i) $(DOCKER_RUN_OPTS)
|
||||
|
||||
IN_DOCKER ?= true
|
||||
DOCKER_BUILD_PLATFORMS ?= linux/amd64,linux/arm64
|
||||
|
||||
.PHONY: default
|
||||
default: binary
|
||||
#? default: Run `make generate` and `make binary`
|
||||
default: generate binary
|
||||
|
||||
## Create the "dist" directory
|
||||
#? dist: Create the "dist" directory
|
||||
dist:
|
||||
mkdir -p dist
|
||||
|
||||
## Build Dev Docker image
|
||||
.PHONY: build-dev-image
|
||||
build-dev-image: dist
|
||||
ifneq ("$(IN_DOCKER)", "")
|
||||
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" --build-arg HOST_PWD="$(PWD)" -f build.Dockerfile .
|
||||
endif
|
||||
|
||||
## Build Dev Docker image without cache
|
||||
.PHONY: build-dev-image-no-cache
|
||||
build-dev-image-no-cache: dist
|
||||
ifneq ("$(IN_DOCKER)", "")
|
||||
docker build $(DOCKER_BUILD_ARGS) --no-cache -t "$(TRAEFIK_DEV_IMAGE)" --build-arg HOST_PWD="$(PWD)" -f build.Dockerfile .
|
||||
endif
|
||||
|
||||
## Build WebUI Docker image
|
||||
.PHONY: build-webui-image
|
||||
#? build-webui-image: Build WebUI Docker image
|
||||
build-webui-image:
|
||||
docker build -t traefik-webui -f webui/Dockerfile webui
|
||||
|
||||
## Clean WebUI static generated assets
|
||||
.PHONY: clean-webui
|
||||
#? clean-webui: Clean WebUI static generated assets
|
||||
clean-webui:
|
||||
rm -r webui/static
|
||||
mkdir -p webui/static
|
||||
printf 'For more information see `webui/readme.md`' > webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md
|
||||
|
||||
## Generate WebUI
|
||||
webui/static/index.html:
|
||||
$(MAKE) build-webui-image
|
||||
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui npm run build:nc
|
||||
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ./static
|
||||
|
||||
.PHONY: generate-webui
|
||||
#? generate-webui: Generate WebUI
|
||||
generate-webui: webui/static/index.html
|
||||
|
||||
## Build the binary
|
||||
.PHONY: generate
|
||||
#? generate: Generate code (Dynamic and Static configuration documentation reference files)
|
||||
generate:
|
||||
go generate
|
||||
|
||||
.PHONY: binary
|
||||
binary: generate-webui build-dev-image
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate binary
|
||||
#? binary: Build the binary
|
||||
binary: generate-webui dist
|
||||
@echo SHA: $(VERSION) $(CODENAME) $(DATE)
|
||||
CGO_ENABLED=0 GOGC=off GOOS=${GOOS} GOARCH=${GOARCH} go build ${FLAGS[*]} -ldflags "-s -w \
|
||||
-X github.com/traefik/traefik/v3/pkg/version.Version=$(VERSION) \
|
||||
-X github.com/traefik/traefik/v3/pkg/version.Codename=$(CODENAME) \
|
||||
-X github.com/traefik/traefik/v3/pkg/version.BuildDate=$(DATE)" \
|
||||
-installsuffix nocgo -o "./dist/${GOOS}/${GOARCH}/$(BIN_NAME)" ./cmd/traefik
|
||||
|
||||
## Build the linux binary locally
|
||||
.PHONY: binary-debug
|
||||
binary-debug: generate-webui
|
||||
GOOS=linux ./script/make.sh binary
|
||||
binary-linux-arm64: export GOOS := linux
|
||||
binary-linux-arm64: export GOARCH := arm64
|
||||
binary-linux-arm64:
|
||||
@$(MAKE) binary
|
||||
|
||||
binary-linux-amd64: export GOOS := linux
|
||||
binary-linux-amd64: export GOARCH := amd64
|
||||
binary-linux-amd64:
|
||||
@$(MAKE) binary
|
||||
|
||||
binary-windows-amd64: export GOOS := windows
|
||||
binary-windows-amd64: export GOARCH := amd64
|
||||
binary-windows-amd64: export BIN_NAME := traefik.exe
|
||||
binary-windows-amd64:
|
||||
@$(MAKE) binary
|
||||
|
||||
## Build the binary for the standard platforms (linux, darwin, windows)
|
||||
.PHONY: crossbinary-default
|
||||
crossbinary-default: generate-webui build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
|
||||
#? crossbinary-default: Build the binary for the standard platforms (linux, darwin, windows)
|
||||
crossbinary-default: generate generate-webui
|
||||
$(CURDIR)/script/crossbinary-default.sh
|
||||
|
||||
## Build the binary for the standard platforms (linux, darwin, windows) in parallel
|
||||
.PHONY: crossbinary-default-parallel
|
||||
crossbinary-default-parallel:
|
||||
$(MAKE) generate-webui
|
||||
$(MAKE) build-dev-image crossbinary-default
|
||||
|
||||
## Run the unit and integration tests
|
||||
.PHONY: test
|
||||
test: build-dev-image
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_TEST)) ./script/make.sh generate test-unit binary test-integration
|
||||
#? test: Run the unit and integration tests
|
||||
test: test-ui-unit test-unit test-integration
|
||||
|
||||
## Run the unit tests
|
||||
.PHONY: test-unit
|
||||
test-unit: build-dev-image
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_TEST)) ./script/make.sh generate test-unit
|
||||
#? test-unit: Run the unit tests
|
||||
test-unit:
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go test -cover "-coverprofile=cover.out" -v $(TESTFLAGS) ./pkg/... ./cmd/...
|
||||
|
||||
## Run the integration tests
|
||||
.PHONY: test-integration
|
||||
test-integration: build-dev-image
|
||||
-docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
trap 'docker network rm traefik-test-network' EXIT; \
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_TEST)) ./script/make.sh generate binary test-integration
|
||||
#? test-integration: Run the integration tests
|
||||
test-integration: binary
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS)
|
||||
|
||||
.PHONY: test-gateway-api-conformance
|
||||
#? test-gateway-api-conformance: Run the conformance tests
|
||||
test-gateway-api-conformance: build-image-dirty
|
||||
# In case of a new Minor/Major version, the k8sConformanceTraefikVersion needs to be updated.
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -test.run K8sConformanceSuite -k8sConformance -k8sConformanceTraefikVersion="v3.3" $(TESTFLAGS)
|
||||
|
||||
.PHONY: test-ui-unit
|
||||
#? test-ui-unit: Run the unit tests for the webui
|
||||
test-ui-unit:
|
||||
$(MAKE) build-webui-image
|
||||
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui yarn --cwd webui install
|
||||
docker run --rm -v "$(PWD)/webui/static":'/src/webui/static' traefik-webui yarn --cwd webui test:unit:ci
|
||||
|
||||
## Pull all images for integration tests
|
||||
.PHONY: pull-images
|
||||
#? pull-images: Pull all Docker images to avoid timeout during integration tests
|
||||
pull-images:
|
||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml \
|
||||
| awk '{print $$2}' \
|
||||
@ -128,84 +119,81 @@ pull-images:
|
||||
| uniq \
|
||||
| xargs -P 6 -n 1 docker pull
|
||||
|
||||
## Validate code and docs
|
||||
.PHONY: lint
|
||||
#? lint: Run golangci-lint
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: validate-files
|
||||
validate-files: build-dev-image
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell
|
||||
bash $(CURDIR)/script/validate-shell-script.sh
|
||||
#? validate-files: Validate code and docs
|
||||
validate-files:
|
||||
$(foreach exec,$(LINT_EXECUTABLES),\
|
||||
$(if $(shell which $(exec)),,$(error "No $(exec) in PATH")))
|
||||
$(CURDIR)/script/validate-vendor.sh
|
||||
$(CURDIR)/script/validate-misspell.sh
|
||||
$(CURDIR)/script/validate-shell-script.sh
|
||||
|
||||
## Validate code, docs, and vendor
|
||||
.PHONY: validate
|
||||
validate: build-dev-image
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell validate-vendor
|
||||
bash $(CURDIR)/script/validate-shell-script.sh
|
||||
#? validate: Validate code, docs, and vendor
|
||||
validate: lint validate-files
|
||||
|
||||
# Target for building images for multiple architectures.
|
||||
.PHONY: multi-arch-image-%
|
||||
multi-arch-image-%: binary-linux-amd64 binary-linux-arm64
|
||||
docker buildx build $(DOCKER_BUILDX_ARGS) -t traefik/traefik:$* --platform=$(DOCKER_BUILD_PLATFORMS) -f Dockerfile .
|
||||
|
||||
|
||||
## Clean up static directory and build a Docker Traefik image
|
||||
.PHONY: build-image
|
||||
build-image: clean-webui binary
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
#? build-image: Clean up static directory and build a Docker Traefik image
|
||||
build-image: export DOCKER_BUILDX_ARGS := --load
|
||||
build-image: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH)
|
||||
build-image: clean-webui
|
||||
@$(MAKE) multi-arch-image-latest
|
||||
|
||||
## Build a Docker Traefik image without re-building the webui
|
||||
.PHONY: build-image-dirty
|
||||
build-image-dirty: binary
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
#? build-image-dirty: Build a Docker Traefik image without re-building the webui when it's already built
|
||||
build-image-dirty: export DOCKER_BUILDX_ARGS := --load
|
||||
build-image-dirty: export DOCKER_BUILD_PLATFORMS := linux/$(GOARCH)
|
||||
build-image-dirty:
|
||||
@$(MAKE) multi-arch-image-latest
|
||||
|
||||
## Locally build traefik for linux, then shove it an alpine image, with basic tools.
|
||||
.PHONY: build-image-debug
|
||||
build-image-debug: binary-debug
|
||||
docker build -t $(TRAEFIK_IMAGE) -f debug.Dockerfile .
|
||||
|
||||
## Start a shell inside the build env
|
||||
.PHONY: shell
|
||||
shell: build-dev-image
|
||||
$(DOCKER_RUN_TRAEFIK) /bin/bash
|
||||
|
||||
## Build documentation site
|
||||
.PHONY: docs
|
||||
#? docs: Build documentation site
|
||||
docs:
|
||||
make -C ./docs docs
|
||||
|
||||
## Serve the documentation site locally
|
||||
.PHONY: docs-serve
|
||||
#? docs-serve: Serve the documentation site locally
|
||||
docs-serve:
|
||||
make -C ./docs docs-serve
|
||||
|
||||
## Pull image for doc building
|
||||
.PHONY: docs-pull-images
|
||||
#? docs-pull-images: Pull image for doc building
|
||||
docs-pull-images:
|
||||
make -C ./docs docs-pull-images
|
||||
|
||||
## Generate CRD clientset and CRD manifests
|
||||
.PHONY: generate-crd
|
||||
#? generate-crd: Generate CRD clientset and CRD manifests
|
||||
generate-crd:
|
||||
@$(CURDIR)/script/code-gen.sh
|
||||
|
||||
## Generate code from dynamic configuration https://github.com/traefik/genconf
|
||||
.PHONY: generate-genconf
|
||||
#? generate-genconf: Generate code from dynamic configuration github.com/traefik/genconf
|
||||
generate-genconf:
|
||||
go run ./cmd/internal/gen/
|
||||
|
||||
## Create packages for the release
|
||||
.PHONY: release-packages
|
||||
release-packages: generate-webui build-dev-image
|
||||
rm -rf dist
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) goreleaser release --skip-publish -p 2 --timeout="90m"
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
||||
--exclude-vcs \
|
||||
--exclude .idea \
|
||||
--exclude .travis \
|
||||
--exclude .semaphoreci \
|
||||
--exclude .github \
|
||||
--exclude dist .
|
||||
$(if $(IN_DOCKER),$(DOCKER_RUN_TRAEFIK_NOTTY)) chown -R $(shell id -u):$(shell id -g) dist/
|
||||
#? release-packages: Create packages for the release
|
||||
release-packages: generate-webui
|
||||
$(CURDIR)/script/release-packages.sh
|
||||
|
||||
## Format the Code
|
||||
.PHONY: fmt
|
||||
#? fmt: Format the Code
|
||||
fmt:
|
||||
gofmt -s -l -w $(SRCS)
|
||||
|
||||
.PHONY: run-dev
|
||||
run-dev:
|
||||
go generate
|
||||
GO111MODULE=on go build ./cmd/traefik
|
||||
./traefik
|
||||
.PHONY: help
|
||||
#? help: Get more info on make commands
|
||||
help: Makefile
|
||||
@echo " Choose a command run in traefik:"
|
||||
@sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /'
|
||||
|
30
README.md
30
README.md
@ -1,9 +1,13 @@
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/content/assets/img/traefik.logo.png" alt="Traefik" title="Traefik" />
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="docs/content/assets/img/traefik.logo-dark.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="docs/content/assets/img/traefik.logo.png">
|
||||
<img alt="Traefik" title="Traefik" src="docs/content/assets/img/traefik.logo.png">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://semaphoreci.com/containous/traefik)
|
||||
[](https://traefik-oss.semaphoreci.com/projects/traefik)
|
||||
[](https://doc.traefik.io/traefik)
|
||||
[](https://goreportcard.com/report/traefik/traefik)
|
||||
[](https://github.com/traefik/traefik/blob/master/LICENSE.md)
|
||||
@ -11,7 +15,7 @@
|
||||
[](https://twitter.com/intent/follow?screen_name=traefik)
|
||||
|
||||
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.
|
||||
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher v2](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.
|
||||
|
||||
---
|
||||
@ -31,7 +35,8 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
|
||||
|
||||
---
|
||||
|
||||
:warning: Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://doc.traefik.io/traefik/).
|
||||
:warning: When migrating to a new major version of Traefik, please refer to the [migration guide](https://doc.traefik.io/traefik/migration/v2-to-v3/) to ensure a smooth transition and to be aware of any breaking changes.
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
@ -54,11 +59,11 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
|
||||
|
||||
- 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)
|
||||
- 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)
|
||||
- WebSocket, HTTP/2, gRPC ready
|
||||
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB 2.X)
|
||||
- Keeps access logs (JSON, CLF)
|
||||
- Fast
|
||||
- Exposes a Rest API
|
||||
@ -68,8 +73,7 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
|
||||
|
||||
- [Docker](https://doc.traefik.io/traefik/providers/docker/) / [Swarm mode](https://doc.traefik.io/traefik/providers/docker/)
|
||||
- [Kubernetes](https://doc.traefik.io/traefik/providers/kubernetes-crd/)
|
||||
- [Marathon](https://doc.traefik.io/traefik/providers/marathon/)
|
||||
- [Rancher](https://doc.traefik.io/traefik/providers/rancher/) (Metadata)
|
||||
- [ECS](https://doc.traefik.io/traefik/providers/ecs/)
|
||||
- [File](https://doc.traefik.io/traefik/providers/file/)
|
||||
|
||||
## Quickstart
|
||||
@ -84,9 +88,7 @@ You can access the simple HTML frontend of Traefik.
|
||||
|
||||
## Documentation
|
||||
|
||||
You can find the complete documentation of Traefik v2 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/).
|
||||
|
||||
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).
|
||||
You can find the complete documentation of Traefik v3 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/).
|
||||
|
||||
## Support
|
||||
|
||||
@ -123,8 +125,8 @@ You can find high level and deep dive videos on [videos.traefik.io](https://vide
|
||||
## Maintainers
|
||||
|
||||
We are strongly promoting a philosophy of openness and sharing, and firmly standing against the elitist closed approach. Being part of the core team should be accessible to anyone who is motivated and want to be part of that journey!
|
||||
This [document](docs/content/contributing/maintainers-guidelines.md) describes how to be part of the core team as well as various responsibilities and guidelines for Traefik maintainers.
|
||||
You can also find more information on our process to review pull requests and manage issues [in this document](docs/content/contributing/maintainers.md).
|
||||
This [document](docs/content/contributing/maintainers-guidelines.md) describes how to be part of the [maintainers' team](docs/content/contributing/maintainers.md) as well as various responsibilities and guidelines for Traefik maintainers.
|
||||
You can also find more information on our process to review pull requests and manage issues [in this document](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Security Policy
|
||||
|
||||
You can join our security mailing list to be aware of the latest announcements from our security team.
|
||||
You can subscribe sending a mail to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
You can subscribe by sending an email to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
|
||||
Reported vulnerabilities can be found on [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=traefik).
|
||||
|
||||
@ -16,7 +16,7 @@ Each version is supported until the next one is released (e.g. 1.1.x will be sup
|
||||
We use [Semantic Versioning](https://semver.org/).
|
||||
|
||||
| Version | Supported |
|
||||
| --------- | ------------------ |
|
||||
|-----------|--------------------|
|
||||
| `2.2.x` | :white_check_mark: |
|
||||
| `< 2.2.x` | :x: |
|
||||
| `1.7.x` | :white_check_mark: |
|
||||
@ -25,4 +25,6 @@ We use [Semantic Versioning](https://semver.org/).
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We want to keep Traefik safe for everyone.
|
||||
If you've discovered a security vulnerability in Traefik, we appreciate your help in disclosing it to us in a responsible manner, using [this form](https://security.traefik.io).
|
||||
If you've discovered a security vulnerability in Traefik,
|
||||
we appreciate your help in disclosing it to us in a responsible manner,
|
||||
by creating a [security advisory](https://github.com/traefik/traefik/security/advisories).
|
||||
|
@ -1,37 +0,0 @@
|
||||
FROM golang:1.20-alpine
|
||||
|
||||
RUN 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
|
||||
ARG DOCKER_VERSION=18.09.7
|
||||
|
||||
# Download docker
|
||||
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'
|
||||
|
||||
# Download golangci-lint binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.52.2
|
||||
|
||||
# Download misspell binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.4.0
|
||||
|
||||
# Download goreleaser binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | sh
|
||||
|
||||
WORKDIR /go/src/github.com/traefik/traefik
|
||||
|
||||
# Because of CVE-2022-24765 (https://github.blog/2022-04-12-git-security-vulnerability-announced/),
|
||||
# we configure git to allow the Traefik codebase path on the Host for docker in docker usages.
|
||||
ARG HOST_PWD=""
|
||||
|
||||
RUN git config --global --add safe.directory "${HOST_PWD}"
|
||||
|
||||
# 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/traefik/traefik
|
@ -4,7 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
)
|
||||
|
||||
// TraefikCmdConfiguration wraps the static configuration and extra parameters.
|
||||
@ -28,6 +28,10 @@ func NewTraefikConfiguration() *TraefikCmdConfiguration {
|
||||
ServersTransport: &static.ServersTransport{
|
||||
MaxIdleConnsPerHost: 200,
|
||||
},
|
||||
TCPServersTransport: &static.TCPServersTransport{
|
||||
DialTimeout: ptypes.Duration(30 * time.Second),
|
||||
DialKeepAlive: ptypes.Duration(15 * time.Second),
|
||||
},
|
||||
},
|
||||
ConfigFile: "",
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/traefik/paerser/cli"
|
||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
)
|
||||
|
||||
// NewCmd builds a new HealthCheck command.
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -80,7 +81,7 @@ func (c Centrifuge) Run(dest string, pkgName string) error {
|
||||
}
|
||||
|
||||
for _, p := range c.pkg.Imports() {
|
||||
if contains(c.IncludedImports, p.Path()) {
|
||||
if slices.Contains(c.IncludedImports, p.Path()) {
|
||||
fls := c.run(p.Scope(), p.Path(), p.Name())
|
||||
|
||||
err = fileWriter{baseDir: filepath.Join(dest, p.Name())}.Write(fls)
|
||||
@ -97,7 +98,7 @@ func (c Centrifuge) run(sc *types.Scope, rootPkg string, pkgName string) map[str
|
||||
files := map[string]*File{}
|
||||
|
||||
for _, name := range sc.Names() {
|
||||
if contains(c.ExcludedTypes, name) {
|
||||
if slices.Contains(c.ExcludedTypes, name) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -107,7 +108,7 @@ func (c Centrifuge) run(sc *types.Scope, rootPkg string, pkgName string) map[str
|
||||
}
|
||||
|
||||
filename := filepath.Base(c.fileSet.File(o.Pos()).Name())
|
||||
if contains(c.ExcludedFiles, path.Join(rootPkg, filename)) {
|
||||
if slices.Contains(c.ExcludedFiles, path.Join(rootPkg, filename)) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -159,7 +160,7 @@ func (c Centrifuge) writeStruct(name string, obj *types.Struct, rootPkg string,
|
||||
b := strings.Builder{}
|
||||
b.WriteString(fmt.Sprintf("type %s struct {\n", name))
|
||||
|
||||
for i := 0; i < obj.NumFields(); i++ {
|
||||
for i := range obj.NumFields() {
|
||||
field := obj.Field(i)
|
||||
|
||||
if !field.Exported() {
|
||||
@ -237,16 +238,6 @@ func extractPackage(t types.Type) string {
|
||||
}
|
||||
}
|
||||
|
||||
func contains(values []string, value string) bool {
|
||||
for _, val := range values {
|
||||
if val == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type fileWriter struct {
|
||||
baseDir string
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const rootPkg = "github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
const rootPkg = "github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
|
||||
const (
|
||||
destModuleName = "github.com/traefik/genconf"
|
||||
@ -57,8 +57,8 @@ func run(dest string) error {
|
||||
}
|
||||
|
||||
centrifuge.IncludedImports = []string{
|
||||
"github.com/traefik/traefik/v2/pkg/tls",
|
||||
"github.com/traefik/traefik/v2/pkg/types",
|
||||
"github.com/traefik/traefik/v3/pkg/tls",
|
||||
"github.com/traefik/traefik/v3/pkg/types",
|
||||
}
|
||||
|
||||
centrifuge.ExcludedTypes = []string{
|
||||
@ -71,8 +71,8 @@ func run(dest string) error {
|
||||
}
|
||||
|
||||
centrifuge.ExcludedFiles = []string{
|
||||
"github.com/traefik/traefik/v2/pkg/types/logs.go",
|
||||
"github.com/traefik/traefik/v2/pkg/types/metrics.go",
|
||||
"github.com/traefik/traefik/v3/pkg/types/logs.go",
|
||||
"github.com/traefik/traefik/v3/pkg/types/metrics.go",
|
||||
}
|
||||
|
||||
centrifuge.TypeCleaner = cleanType
|
||||
@ -87,11 +87,11 @@ func run(dest string) error {
|
||||
}
|
||||
|
||||
func cleanType(typ types.Type, base string) string {
|
||||
if typ.String() == "github.com/traefik/traefik/v2/pkg/tls.FileOrContent" {
|
||||
if typ.String() == "github.com/traefik/traefik/v3/pkg/types.FileOrContent" {
|
||||
return "string"
|
||||
}
|
||||
|
||||
if typ.String() == "[]github.com/traefik/traefik/v2/pkg/tls.FileOrContent" {
|
||||
if typ.String() == "[]github.com/traefik/traefik/v3/pkg/types.FileOrContent" {
|
||||
return "[]string"
|
||||
}
|
||||
|
||||
@ -103,8 +103,8 @@ func cleanType(typ types.Type, base string) string {
|
||||
return strings.ReplaceAll(typ.String(), base+".", "")
|
||||
}
|
||||
|
||||
if strings.Contains(typ.String(), "github.com/traefik/traefik/v2/pkg/") {
|
||||
return strings.ReplaceAll(typ.String(), "github.com/traefik/traefik/v2/pkg/", "")
|
||||
if strings.Contains(typ.String(), "github.com/traefik/traefik/v3/pkg/") {
|
||||
return strings.ReplaceAll(typ.String(), "github.com/traefik/traefik/v3/pkg/", "")
|
||||
}
|
||||
|
||||
return typ.String()
|
||||
@ -114,9 +114,9 @@ func cleanPackage(src string) string {
|
||||
switch src {
|
||||
case "github.com/traefik/paerser/types":
|
||||
return ""
|
||||
case "github.com/traefik/traefik/v2/pkg/tls":
|
||||
case "github.com/traefik/traefik/v3/pkg/tls":
|
||||
return path.Join(destModuleName, destPkg, "tls")
|
||||
case "github.com/traefik/traefik/v2/pkg/types":
|
||||
case "github.com/traefik/traefik/v3/pkg/types":
|
||||
return path.Join(destModuleName, destPkg, "types")
|
||||
default:
|
||||
return src
|
||||
|
113
cmd/traefik/logger.go
Normal file
113
cmd/traefik/logger.go
Normal file
@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/logs"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// hide the first logs before the setup of the logger.
|
||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
||||
}
|
||||
|
||||
func setupLogger(staticConfiguration *static.Configuration) error {
|
||||
// Validate that the experimental flag is set up at this point,
|
||||
// rather than validating the static configuration before the setupLogger call.
|
||||
// This ensures that validation messages are not logged using an un-configured logger.
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil &&
|
||||
(staticConfiguration.Experimental == nil || !staticConfiguration.Experimental.OTLPLogs) {
|
||||
return errors.New("the experimental OTLPLogs feature must be enabled to use OTLP logging")
|
||||
}
|
||||
|
||||
// configure log format
|
||||
w := getLogWriter(staticConfiguration)
|
||||
|
||||
// configure log level
|
||||
logLevel := getLogLevel(staticConfiguration)
|
||||
zerolog.SetGlobalLevel(logLevel)
|
||||
|
||||
// create logger
|
||||
logCtx := zerolog.New(w).With().Timestamp()
|
||||
if logLevel <= zerolog.DebugLevel {
|
||||
logCtx = logCtx.Caller()
|
||||
}
|
||||
|
||||
log.Logger = logCtx.Logger().Level(logLevel)
|
||||
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
|
||||
var err error
|
||||
log.Logger, err = logs.SetupOTelLogger(log.Logger, staticConfiguration.Log.OTLP)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up OpenTelemetry logger: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
zerolog.DefaultContextLogger = &log.Logger
|
||||
|
||||
// Global logrus replacement (related to lib like go-rancher-metadata, docker, etc.)
|
||||
logrus.StandardLogger().Out = logs.NoLevel(log.Logger, zerolog.DebugLevel)
|
||||
|
||||
// configure default standard log.
|
||||
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
|
||||
stdlog.SetOutput(logs.NoLevel(log.Logger, zerolog.DebugLevel))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLogWriter(staticConfiguration *static.Configuration) io.Writer {
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
|
||||
return io.Discard
|
||||
}
|
||||
|
||||
var w io.Writer = os.Stdout
|
||||
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
||||
_, _ = os.OpenFile(staticConfiguration.Log.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
|
||||
w = &lumberjack.Logger{
|
||||
Filename: staticConfiguration.Log.FilePath,
|
||||
MaxSize: staticConfiguration.Log.MaxSize,
|
||||
MaxBackups: staticConfiguration.Log.MaxBackups,
|
||||
MaxAge: staticConfiguration.Log.MaxAge,
|
||||
Compress: true,
|
||||
}
|
||||
}
|
||||
|
||||
if staticConfiguration.Log == nil || staticConfiguration.Log.Format != "json" {
|
||||
w = zerolog.ConsoleWriter{
|
||||
Out: w,
|
||||
TimeFormat: time.RFC3339,
|
||||
NoColor: staticConfiguration.Log != nil && (staticConfiguration.Log.NoColor || len(staticConfiguration.Log.FilePath) > 0),
|
||||
}
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
func getLogLevel(staticConfiguration *static.Configuration) zerolog.Level {
|
||||
levelStr := "error"
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.Level != "" {
|
||||
levelStr = strings.ToLower(staticConfiguration.Log.Level)
|
||||
}
|
||||
|
||||
logLevel, err := zerolog.ParseLevel(strings.ToLower(levelStr))
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("logLevel", levelStr).
|
||||
Msg("Unspecified or invalid log level, setting the level to default (ERROR)...")
|
||||
|
||||
logLevel = zerolog.ErrorLevel
|
||||
}
|
||||
|
||||
return logLevel
|
||||
}
|
@ -3,8 +3,8 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||
"github.com/traefik/traefik/v2/pkg/plugins"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/plugins"
|
||||
)
|
||||
|
||||
const outputDir = "./plugins-storage/"
|
||||
@ -35,12 +35,12 @@ func initPlugins(staticCfg *static.Configuration) (*plugins.Client, map[string]p
|
||||
var err error
|
||||
client, err = plugins.NewClient(opts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, nil, fmt.Errorf("unable to create plugins client: %w", err)
|
||||
}
|
||||
|
||||
err = plugins.SetupRemotePlugins(client, staticCfg.Experimental.Plugins)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, nil, fmt.Errorf("unable to set up plugins environment: %w", err)
|
||||
}
|
||||
|
||||
plgs = staticCfg.Experimental.Plugins
|
||||
|
@ -5,53 +5,58 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"maps"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-systemd/daemon"
|
||||
"github.com/coreos/go-systemd/v22/daemon"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
gokitmetrics "github.com/go-kit/kit/metrics"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spiffe/go-spiffe/v2/workloadapi"
|
||||
"github.com/traefik/paerser/cli"
|
||||
"github.com/traefik/traefik/v2/cmd"
|
||||
"github.com/traefik/traefik/v2/cmd/healthcheck"
|
||||
cmdVersion "github.com/traefik/traefik/v2/cmd/version"
|
||||
tcli "github.com/traefik/traefik/v2/pkg/cli"
|
||||
"github.com/traefik/traefik/v2/pkg/collector"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
"github.com/traefik/traefik/v2/pkg/metrics"
|
||||
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/acme"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/aggregator"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
||||
"github.com/traefik/traefik/v2/pkg/safe"
|
||||
"github.com/traefik/traefik/v2/pkg/server"
|
||||
"github.com/traefik/traefik/v2/pkg/server/middleware"
|
||||
"github.com/traefik/traefik/v2/pkg/server/service"
|
||||
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
|
||||
"github.com/traefik/traefik/v2/pkg/tracing"
|
||||
"github.com/traefik/traefik/v2/pkg/tracing/jaeger"
|
||||
"github.com/traefik/traefik/v2/pkg/types"
|
||||
"github.com/traefik/traefik/v2/pkg/version"
|
||||
"github.com/vulcand/oxy/v2/roundrobin"
|
||||
"github.com/traefik/traefik/v3/cmd"
|
||||
"github.com/traefik/traefik/v3/cmd/healthcheck"
|
||||
cmdVersion "github.com/traefik/traefik/v3/cmd/version"
|
||||
_ "github.com/traefik/traefik/v3/init"
|
||||
tcli "github.com/traefik/traefik/v3/pkg/cli"
|
||||
"github.com/traefik/traefik/v3/pkg/collector"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/logs"
|
||||
"github.com/traefik/traefik/v3/pkg/metrics"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/acme"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/aggregator"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/tailscale"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/traefik"
|
||||
"github.com/traefik/traefik/v3/pkg/proxy"
|
||||
"github.com/traefik/traefik/v3/pkg/proxy/httputil"
|
||||
"github.com/traefik/traefik/v3/pkg/safe"
|
||||
"github.com/traefik/traefik/v3/pkg/server"
|
||||
"github.com/traefik/traefik/v3/pkg/server/middleware"
|
||||
"github.com/traefik/traefik/v3/pkg/server/service"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// traefik config inits
|
||||
tConfig := cmd.NewTraefikConfiguration()
|
||||
|
||||
loaders := []cli.ResourceLoader{&tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}}
|
||||
loaders := []cli.ResourceLoader{&tcli.DeprecationLoader{}, &tcli.FileLoader{}, &tcli.FlagLoader{}, &tcli.EnvLoader{}}
|
||||
|
||||
cmdTraefik := &cli.Command{
|
||||
Name: "traefik",
|
||||
@ -78,7 +83,7 @@ Complete documentation is available at https://traefik.io`,
|
||||
|
||||
err = cli.Execute(cmdTraefik)
|
||||
if err != nil {
|
||||
stdlog.Println(err)
|
||||
log.Error().Err(err).Msg("Command error")
|
||||
logrus.Exit(1)
|
||||
}
|
||||
|
||||
@ -86,27 +91,26 @@ Complete documentation is available at https://traefik.io`,
|
||||
}
|
||||
|
||||
func runCmd(staticConfiguration *static.Configuration) error {
|
||||
configureLogging(staticConfiguration)
|
||||
if err := setupLogger(staticConfiguration); err != nil {
|
||||
return fmt.Errorf("setting up logger: %w", err)
|
||||
}
|
||||
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
if err := roundrobin.SetDefaultWeight(0); err != nil {
|
||||
log.WithoutContext().Errorf("Could not set round robin 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)
|
||||
log.Info().Str("version", version.Version).
|
||||
Msgf("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)
|
||||
log.Error().Err(err).Msg("Could not marshal static configuration")
|
||||
log.Debug().Interface("staticConfiguration", staticConfiguration).Msg("Static configuration loaded [struct]")
|
||||
} else {
|
||||
log.WithoutContext().Debugf("Static configuration loaded %s", string(jsonConf))
|
||||
log.Debug().RawJSON("staticConfiguration", jsonConf).Msg("Static configuration loaded [json]")
|
||||
}
|
||||
|
||||
if staticConfiguration.Global.CheckNewVersion {
|
||||
@ -131,16 +135,16 @@ func runCmd(staticConfiguration *static.Configuration) error {
|
||||
|
||||
sent, err := daemon.SdNotify(false, "READY=1")
|
||||
if !sent && err != nil {
|
||||
log.WithoutContext().Errorf("Failed to notify: %v", err)
|
||||
log.Error().Err(err).Msg("Failed to notify")
|
||||
}
|
||||
|
||||
t, err := daemon.SdWatchdogEnabled(false)
|
||||
if err != nil {
|
||||
log.WithoutContext().Errorf("Could not enable Watchdog: %v", err)
|
||||
log.Error().Err(err).Msg("Could not enable Watchdog")
|
||||
} else if t != 0 {
|
||||
// Send a ping each half time given
|
||||
t /= 2
|
||||
log.WithoutContext().Infof("Watchdog activated with timer duration %s", t)
|
||||
log.Info().Msgf("Watchdog activated with timer duration %s", t)
|
||||
safe.Go(func() {
|
||||
tick := time.Tick(t)
|
||||
for range tick {
|
||||
@ -151,17 +155,17 @@ func runCmd(staticConfiguration *static.Configuration) error {
|
||||
|
||||
if staticConfiguration.Ping == nil || errHealthCheck == nil {
|
||||
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
|
||||
log.WithoutContext().Error("Fail to tick watchdog")
|
||||
log.Error().Msg("Fail to tick watchdog")
|
||||
}
|
||||
} else {
|
||||
log.WithoutContext().Error(errHealthCheck)
|
||||
log.Error().Err(errHealthCheck).Send()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
svr.Wait()
|
||||
log.WithoutContext().Info("Shutting down")
|
||||
log.Info().Msg("Shutting down")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -188,11 +192,30 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider)
|
||||
acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider, routinesPool)
|
||||
|
||||
// Tailscale
|
||||
|
||||
tsProviders := initTailscaleProviders(staticConfiguration, providerAggregator)
|
||||
|
||||
// Observability
|
||||
|
||||
metricRegistries := registerMetricClients(staticConfiguration.Metrics)
|
||||
var semConvMetricRegistry *metrics.SemConvMetricsRegistry
|
||||
if staticConfiguration.Metrics != nil && staticConfiguration.Metrics.OTLP != nil {
|
||||
semConvMetricRegistry, err = metrics.NewSemConvMetricRegistry(ctx, staticConfiguration.Metrics.OTLP)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create SemConv metric registry: %w", err)
|
||||
}
|
||||
}
|
||||
metricsRegistry := metrics.NewMultiRegistry(metricRegistries)
|
||||
accessLog := setupAccessLog(staticConfiguration.AccessLog)
|
||||
tracer, tracerCloser := setupTracing(staticConfiguration.Tracing)
|
||||
observabilityMgr := middleware.NewObservabilityMgr(*staticConfiguration, metricsRegistry, semConvMetricRegistry, accessLog, tracer, tracerCloser)
|
||||
|
||||
// Entrypoints
|
||||
|
||||
serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints, staticConfiguration.HostResolver)
|
||||
serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints, staticConfiguration.HostResolver, metricsRegistry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -202,15 +225,29 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if staticConfiguration.Pilot != nil {
|
||||
log.WithoutContext().Warn("Traefik Pilot has been removed.")
|
||||
if staticConfiguration.API != nil {
|
||||
version.DisableDashboardAd = staticConfiguration.API.DisableDashboardAd
|
||||
}
|
||||
|
||||
// Plugins
|
||||
pluginLogger := log.Ctx(ctx).With().Logger()
|
||||
hasPlugins := staticConfiguration.Experimental != nil && (staticConfiguration.Experimental.Plugins != nil || staticConfiguration.Experimental.LocalPlugins != nil)
|
||||
if hasPlugins {
|
||||
pluginsList := slices.Collect(maps.Keys(staticConfiguration.Experimental.Plugins))
|
||||
pluginsList = append(pluginsList, slices.Collect(maps.Keys(staticConfiguration.Experimental.LocalPlugins))...)
|
||||
|
||||
pluginLogger = pluginLogger.With().Strs("plugins", pluginsList).Logger()
|
||||
pluginLogger.Info().Msg("Loading plugins...")
|
||||
}
|
||||
|
||||
pluginBuilder, err := createPluginBuilder(staticConfiguration)
|
||||
if err != nil && staticConfiguration.Experimental != nil && staticConfiguration.Experimental.AbortOnPluginFailure {
|
||||
return nil, fmt.Errorf("plugin: failed to create plugin builder: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
log.WithoutContext().WithError(err).Error("Plugins are disabled because an error has occurred.")
|
||||
pluginLogger.Err(err).Msg("Plugins are disabled because an error has occurred.")
|
||||
} else if hasPlugins {
|
||||
pluginLogger.Info().Msg("Plugins loaded.")
|
||||
}
|
||||
|
||||
// Providers plugins
|
||||
@ -231,37 +268,41 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
}
|
||||
}
|
||||
|
||||
// Traefik Hub
|
||||
|
||||
if staticConfiguration.Hub != nil {
|
||||
if err = providerAggregator.AddProvider(staticConfiguration.Hub); err != nil {
|
||||
return nil, fmt.Errorf("adding Traefik Hub provider: %w", err)
|
||||
}
|
||||
|
||||
// API is mandatory for Traefik Hub to access the dynamic configuration.
|
||||
if staticConfiguration.API == nil {
|
||||
staticConfiguration.API = &static.API{}
|
||||
}
|
||||
}
|
||||
|
||||
// Metrics
|
||||
|
||||
metricRegistries := registerMetricClients(staticConfiguration.Metrics)
|
||||
metricsRegistry := metrics.NewMultiRegistry(metricRegistries)
|
||||
|
||||
// Service manager factory
|
||||
|
||||
roundTripperManager := service.NewRoundTripperManager()
|
||||
var spiffeX509Source *workloadapi.X509Source
|
||||
if staticConfiguration.Spiffe != nil && staticConfiguration.Spiffe.WorkloadAPIAddr != "" {
|
||||
log.Info().Str("workloadAPIAddr", staticConfiguration.Spiffe.WorkloadAPIAddr).
|
||||
Msg("Waiting on SPIFFE SVID delivery")
|
||||
|
||||
spiffeX509Source, err = workloadapi.NewX509Source(
|
||||
ctx,
|
||||
workloadapi.WithClientOptions(
|
||||
workloadapi.WithAddr(
|
||||
staticConfiguration.Spiffe.WorkloadAPIAddr,
|
||||
),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create SPIFFE x509 source: %w", err)
|
||||
}
|
||||
log.Info().Msg("Successfully obtained SPIFFE SVID.")
|
||||
}
|
||||
|
||||
transportManager := service.NewTransportManager(spiffeX509Source)
|
||||
|
||||
var proxyBuilder service.ProxyBuilder = httputil.NewProxyBuilder(transportManager, semConvMetricRegistry)
|
||||
if staticConfiguration.Experimental != nil && staticConfiguration.Experimental.FastProxy != nil {
|
||||
proxyBuilder = proxy.NewSmartBuilder(transportManager, proxyBuilder, *staticConfiguration.Experimental.FastProxy)
|
||||
}
|
||||
|
||||
dialerManager := tcp.NewDialerManager(spiffeX509Source)
|
||||
acmeHTTPHandler := getHTTPChallengeHandler(acmeProviders, httpChallengeProvider)
|
||||
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry, roundTripperManager, acmeHTTPHandler)
|
||||
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, observabilityMgr, transportManager, proxyBuilder, acmeHTTPHandler)
|
||||
|
||||
// Router factory
|
||||
|
||||
accessLog := setupAccessLog(staticConfiguration.AccessLog)
|
||||
tracer := setupTracing(staticConfiguration.Tracing)
|
||||
|
||||
chainBuilder := middleware.NewChainBuilder(metricsRegistry, accessLog, tracer)
|
||||
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder, pluginBuilder, metricsRegistry)
|
||||
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, observabilityMgr, pluginBuilder, dialerManager)
|
||||
|
||||
// Watcher
|
||||
|
||||
@ -291,14 +332,16 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
|
||||
// Server Transports
|
||||
watcher.AddListener(func(conf dynamic.Configuration) {
|
||||
roundTripperManager.Update(conf.HTTP.ServersTransports)
|
||||
transportManager.Update(conf.HTTP.ServersTransports)
|
||||
proxyBuilder.Update(conf.HTTP.ServersTransports)
|
||||
dialerManager.Update(conf.TCP.ServersTransports)
|
||||
})
|
||||
|
||||
// Switch router
|
||||
watcher.AddListener(switchRouter(routerFactory, serverEntryPointsTCP, serverEntryPointsUDP))
|
||||
|
||||
// Metrics
|
||||
if metricsRegistry.IsEpEnabled() || metricsRegistry.IsSvcEnabled() {
|
||||
if metricsRegistry.IsEpEnabled() || metricsRegistry.IsRouterEnabled() || metricsRegistry.IsSvcEnabled() {
|
||||
var eps []string
|
||||
for key := range serverEntryPointsTCP {
|
||||
eps = append(eps, key)
|
||||
@ -311,13 +354,22 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
// TLS challenge
|
||||
watcher.AddListener(tlsChallengeProvider.ListenConfiguration)
|
||||
|
||||
// ACME
|
||||
// Certificate Resolvers
|
||||
|
||||
resolverNames := map[string]struct{}{}
|
||||
|
||||
// ACME
|
||||
for _, p := range acmeProviders {
|
||||
resolverNames[p.ResolverName] = struct{}{}
|
||||
watcher.AddListener(p.ListenConfiguration)
|
||||
}
|
||||
|
||||
// Tailscale
|
||||
for _, p := range tsProviders {
|
||||
resolverNames[p.ResolverName] = struct{}{}
|
||||
watcher.AddListener(p.HandleConfigUpdate)
|
||||
}
|
||||
|
||||
// Certificate resolver logs
|
||||
watcher.AddListener(func(config dynamic.Configuration) {
|
||||
for rtName, rt := range config.HTTP.Routers {
|
||||
@ -325,16 +377,14 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := resolverNames[rt.TLS.CertResolver]; !ok &&
|
||||
// "traefik-hub" is an allowed certificate resolver name in a Traefik Hub Experimental feature context.
|
||||
// It is used to activate its own certificate resolution, even though it is not a "classical" traefik certificate resolver.
|
||||
(staticConfiguration.Hub == nil || rt.TLS.CertResolver != "traefik-hub") {
|
||||
log.WithoutContext().Errorf("the router %s uses a non-existent resolver: %s", rtName, rt.TLS.CertResolver)
|
||||
if _, ok := resolverNames[rt.TLS.CertResolver]; !ok {
|
||||
log.Error().Err(err).Str(logs.RouterName, rtName).Str("certificateResolver", rt.TLS.CertResolver).
|
||||
Msg("Router uses a nonexistent certificate resolver")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return server.NewServer(routinesPool, serverEntryPointsTCP, serverEntryPointsUDP, watcher, chainBuilder, accessLog), nil
|
||||
return server.NewServer(routinesPool, serverEntryPointsTCP, serverEntryPointsUDP, watcher, observabilityMgr), nil
|
||||
}
|
||||
|
||||
func getHTTPChallengeHandler(acmeProviders []*acme.Provider, httpChallengeProvider http.Handler) http.Handler {
|
||||
@ -350,16 +400,27 @@ func getHTTPChallengeHandler(acmeProviders []*acme.Provider, httpChallengeProvid
|
||||
|
||||
func getDefaultsEntrypoints(staticConfiguration *static.Configuration) []string {
|
||||
var defaultEntryPoints []string
|
||||
|
||||
// Determines if at least one EntryPoint is configured to be used by default.
|
||||
var hasDefinedDefaults bool
|
||||
for _, ep := range staticConfiguration.EntryPoints {
|
||||
if ep.AsDefault {
|
||||
hasDefinedDefaults = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for name, cfg := range staticConfiguration.EntryPoints {
|
||||
// Traefik Hub entryPoint should not be part of the set of default entryPoints.
|
||||
if hub.APIEntrypoint == name || hub.TunnelEntrypoint == name {
|
||||
// By default all entrypoints are considered.
|
||||
// If at least one is flagged, then only flagged entrypoints are included.
|
||||
if hasDefinedDefaults && !cfg.AsDefault {
|
||||
continue
|
||||
}
|
||||
|
||||
protocol, err := cfg.GetProtocol()
|
||||
if err != nil {
|
||||
// Should never happen because Traefik should not start if protocol is invalid.
|
||||
log.WithoutContext().Errorf("Invalid protocol: %v", err)
|
||||
log.Error().Err(err).Msg("Invalid protocol")
|
||||
}
|
||||
|
||||
if protocol != "udp" && name != static.DefaultInternalEntryPointName {
|
||||
@ -367,7 +428,7 @@ func getDefaultsEntrypoints(staticConfiguration *static.Configuration) []string
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(defaultEntryPoints)
|
||||
slices.Sort(defaultEntryPoints)
|
||||
return defaultEntryPoints
|
||||
}
|
||||
|
||||
@ -382,8 +443,8 @@ func switchRouter(routerFactory *server.RouterFactory, serverEntryPointsTCP serv
|
||||
}
|
||||
}
|
||||
|
||||
// initACMEProvider creates an acme provider from the ACME part of globalConfiguration.
|
||||
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider) []*acme.Provider {
|
||||
// initACMEProvider creates and registers acme.Provider instances corresponding to the configured ACME certificate resolvers.
|
||||
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager, httpChallengeProvider, tlsChallengeProvider challenge.Provider, routinesPool *safe.Pool) []*acme.Provider {
|
||||
localStores := map[string]*acme.LocalStore{}
|
||||
|
||||
var resolvers []*acme.Provider
|
||||
@ -393,7 +454,7 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
|
||||
}
|
||||
|
||||
if localStores[resolver.ACME.Storage] == nil {
|
||||
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage)
|
||||
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage, routinesPool)
|
||||
}
|
||||
|
||||
p := &acme.Provider{
|
||||
@ -405,7 +466,7 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
|
||||
}
|
||||
|
||||
if err := providerAggregator.AddProvider(p); err != nil {
|
||||
log.WithoutContext().Errorf("The ACME resolver %q is skipped from the resolvers list because: %v", name, err)
|
||||
log.Error().Err(err).Str("resolver", name).Msg("The ACME resolve is skipped from the resolvers list")
|
||||
continue
|
||||
}
|
||||
|
||||
@ -419,6 +480,27 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
|
||||
return resolvers
|
||||
}
|
||||
|
||||
// initTailscaleProviders creates and registers tailscale.Provider instances corresponding to the configured Tailscale certificate resolvers.
|
||||
func initTailscaleProviders(cfg *static.Configuration, providerAggregator *aggregator.ProviderAggregator) []*tailscale.Provider {
|
||||
var providers []*tailscale.Provider
|
||||
for name, resolver := range cfg.CertificatesResolvers {
|
||||
if resolver.Tailscale == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
tsProvider := &tailscale.Provider{ResolverName: name}
|
||||
|
||||
if err := providerAggregator.AddProvider(tsProvider); err != nil {
|
||||
log.Error().Err(err).Str(logs.ProviderName, name).Msg("Unable to create Tailscale provider")
|
||||
continue
|
||||
}
|
||||
|
||||
providers = append(providers, tsProvider)
|
||||
}
|
||||
|
||||
return providers
|
||||
}
|
||||
|
||||
func registerMetricClients(metricsConfig *types.Metrics) []metrics.Registry {
|
||||
if metricsConfig == nil {
|
||||
return nil
|
||||
@ -427,42 +509,59 @@ func registerMetricClients(metricsConfig *types.Metrics) []metrics.Registry {
|
||||
var registries []metrics.Registry
|
||||
|
||||
if metricsConfig.Prometheus != nil {
|
||||
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "prometheus"))
|
||||
prometheusRegister := metrics.RegisterPrometheus(ctx, metricsConfig.Prometheus)
|
||||
logger := log.With().Str(logs.MetricsProviderName, "prometheus").Logger()
|
||||
|
||||
prometheusRegister := metrics.RegisterPrometheus(logger.WithContext(context.Background()), metricsConfig.Prometheus)
|
||||
if prometheusRegister != nil {
|
||||
registries = append(registries, prometheusRegister)
|
||||
log.FromContext(ctx).Debug("Configured Prometheus metrics")
|
||||
logger.Debug().Msg("Configured Prometheus metrics")
|
||||
}
|
||||
}
|
||||
|
||||
if metricsConfig.Datadog != nil {
|
||||
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "datadog"))
|
||||
registries = append(registries, metrics.RegisterDatadog(ctx, metricsConfig.Datadog))
|
||||
log.FromContext(ctx).Debugf("Configured Datadog metrics: pushing to %s once every %s",
|
||||
metricsConfig.Datadog.Address, metricsConfig.Datadog.PushInterval)
|
||||
logger := log.With().Str(logs.MetricsProviderName, "datadog").Logger()
|
||||
|
||||
registries = append(registries, metrics.RegisterDatadog(logger.WithContext(context.Background()), metricsConfig.Datadog))
|
||||
logger.Debug().
|
||||
Str("address", metricsConfig.Datadog.Address).
|
||||
Str("pushInterval", metricsConfig.Datadog.PushInterval.String()).
|
||||
Msgf("Configured Datadog metrics")
|
||||
}
|
||||
|
||||
if metricsConfig.StatsD != nil {
|
||||
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "statsd"))
|
||||
registries = append(registries, metrics.RegisterStatsd(ctx, metricsConfig.StatsD))
|
||||
log.FromContext(ctx).Debugf("Configured StatsD metrics: pushing to %s once every %s",
|
||||
metricsConfig.StatsD.Address, metricsConfig.StatsD.PushInterval)
|
||||
}
|
||||
logger := log.With().Str(logs.MetricsProviderName, "statsd").Logger()
|
||||
|
||||
if metricsConfig.InfluxDB != nil {
|
||||
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "influxdb"))
|
||||
registries = append(registries, metrics.RegisterInfluxDB(ctx, metricsConfig.InfluxDB))
|
||||
log.FromContext(ctx).Debugf("Configured InfluxDB metrics: pushing to %s once every %s",
|
||||
metricsConfig.InfluxDB.Address, metricsConfig.InfluxDB.PushInterval)
|
||||
registries = append(registries, metrics.RegisterStatsd(logger.WithContext(context.Background()), metricsConfig.StatsD))
|
||||
logger.Debug().
|
||||
Str("address", metricsConfig.StatsD.Address).
|
||||
Str("pushInterval", metricsConfig.StatsD.PushInterval.String()).
|
||||
Msg("Configured StatsD metrics")
|
||||
}
|
||||
|
||||
if metricsConfig.InfluxDB2 != nil {
|
||||
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "influxdb2"))
|
||||
influxDB2Register := metrics.RegisterInfluxDB2(ctx, metricsConfig.InfluxDB2)
|
||||
logger := log.With().Str(logs.MetricsProviderName, "influxdb2").Logger()
|
||||
|
||||
influxDB2Register := metrics.RegisterInfluxDB2(logger.WithContext(context.Background()), metricsConfig.InfluxDB2)
|
||||
if influxDB2Register != nil {
|
||||
registries = append(registries, influxDB2Register)
|
||||
log.FromContext(ctx).Debugf("Configured InfluxDB v2 metrics: pushing to %s (%s org/%s bucket) once every %s",
|
||||
metricsConfig.InfluxDB2.Address, metricsConfig.InfluxDB2.Org, metricsConfig.InfluxDB2.Bucket, metricsConfig.InfluxDB2.PushInterval)
|
||||
logger.Debug().
|
||||
Str("address", metricsConfig.InfluxDB2.Address).
|
||||
Str("bucket", metricsConfig.InfluxDB2.Bucket).
|
||||
Str("organization", metricsConfig.InfluxDB2.Org).
|
||||
Str("pushInterval", metricsConfig.InfluxDB2.PushInterval.String()).
|
||||
Msg("Configured InfluxDB v2 metrics")
|
||||
}
|
||||
}
|
||||
|
||||
if metricsConfig.OTLP != nil {
|
||||
logger := log.With().Str(logs.MetricsProviderName, "openTelemetry").Logger()
|
||||
|
||||
openTelemetryRegistry := metrics.RegisterOpenTelemetry(logger.WithContext(context.Background()), metricsConfig.OTLP)
|
||||
if openTelemetryRegistry != nil {
|
||||
registries = append(registries, openTelemetryRegistry)
|
||||
logger.Debug().
|
||||
Str("pushInterval", metricsConfig.OTLP.PushInterval.String()).
|
||||
Msg("Configured OpenTelemetry metrics")
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,7 +569,7 @@ func registerMetricClients(metricsConfig *types.Metrics) []metrics.Registry {
|
||||
}
|
||||
|
||||
func appendCertMetric(gauge gokitmetrics.Gauge, certificate *x509.Certificate) {
|
||||
sort.Strings(certificate.DNSNames)
|
||||
slices.Sort(certificate.DNSNames)
|
||||
|
||||
labels := []string{
|
||||
"cn", certificate.Subject.CommonName,
|
||||
@ -490,130 +589,25 @@ func setupAccessLog(conf *types.AccessLog) *accesslog.Handler {
|
||||
|
||||
accessLoggerMiddleware, err := accesslog.NewHandler(conf)
|
||||
if err != nil {
|
||||
log.WithoutContext().Warnf("Unable to create access logger: %v", err)
|
||||
log.Warn().Err(err).Msg("Unable to create access logger")
|
||||
return nil
|
||||
}
|
||||
|
||||
return accessLoggerMiddleware
|
||||
}
|
||||
|
||||
func setupTracing(conf *static.Tracing) *tracing.Tracing {
|
||||
func setupTracing(conf *static.Tracing) (*tracing.Tracer, io.Closer) {
|
||||
if conf == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var backend tracing.Backend
|
||||
|
||||
if conf.Jaeger != nil {
|
||||
backend = conf.Jaeger
|
||||
}
|
||||
|
||||
if conf.Zipkin != nil {
|
||||
if backend != nil {
|
||||
log.WithoutContext().Error("Multiple tracing backend are not supported: cannot create Zipkin backend.")
|
||||
} else {
|
||||
backend = conf.Zipkin
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Datadog != nil {
|
||||
if backend != nil {
|
||||
log.WithoutContext().Error("Multiple tracing backend are not supported: cannot create Datadog backend.")
|
||||
} else {
|
||||
backend = conf.Datadog
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Instana != nil {
|
||||
if backend != nil {
|
||||
log.WithoutContext().Error("Multiple tracing backend are not supported: cannot create Instana backend.")
|
||||
} else {
|
||||
backend = conf.Instana
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Haystack != nil {
|
||||
if backend != nil {
|
||||
log.WithoutContext().Error("Multiple tracing backend are not supported: cannot create Haystack backend.")
|
||||
} else {
|
||||
backend = conf.Haystack
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Elastic != nil {
|
||||
if backend != nil {
|
||||
log.WithoutContext().Error("Multiple tracing backend are not supported: cannot create Elastic backend.")
|
||||
} else {
|
||||
backend = conf.Elastic
|
||||
}
|
||||
}
|
||||
|
||||
if backend == nil {
|
||||
log.WithoutContext().Debug("Could not initialize tracing, using Jaeger by default")
|
||||
defaultBackend := &jaeger.Config{}
|
||||
defaultBackend.SetDefaults()
|
||||
backend = defaultBackend
|
||||
}
|
||||
|
||||
tracer, err := tracing.NewTracing(conf.ServiceName, conf.SpanNameLimit, backend)
|
||||
tracer, closer, err := tracing.NewTracing(conf)
|
||||
if err != nil {
|
||||
log.WithoutContext().Warnf("Unable to create tracer: %v", err)
|
||||
return nil
|
||||
}
|
||||
return tracer
|
||||
}
|
||||
|
||||
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)
|
||||
log.Warn().Err(err).Msg("Unable to create tracer")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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, 0o755); 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)
|
||||
}
|
||||
}
|
||||
return tracer, closer
|
||||
}
|
||||
|
||||
func checkNewVersion() {
|
||||
@ -626,16 +620,16 @@ func checkNewVersion() {
|
||||
}
|
||||
|
||||
func stats(staticConfiguration *static.Configuration) {
|
||||
logger := log.WithoutContext()
|
||||
logger := log.With().Logger()
|
||||
|
||||
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://doc.traefik.io/traefik/contributing/data-collection/`)
|
||||
logger.Info().Msg(`Stats collection is enabled.`)
|
||||
logger.Info().Msg(`Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.`)
|
||||
logger.Info().Msg(`Help us improve Traefik by leaving this feature on :)`)
|
||||
logger.Info().Msg(`More details on: https://doc.traefik.io/traefik/contributing/data-collection/`)
|
||||
collect(staticConfiguration)
|
||||
} else {
|
||||
logger.Info(`
|
||||
logger.Info().Msg(`
|
||||
Stats collection is disabled.
|
||||
Help us improve Traefik by turning this feature on :)
|
||||
More details on: https://doc.traefik.io/traefik/contributing/data-collection/
|
||||
@ -648,7 +642,7 @@ func collect(staticConfiguration *static.Configuration) {
|
||||
safe.Go(func() {
|
||||
for time.Sleep(10 * time.Minute); ; <-ticker {
|
||||
if err := collector.Collect(staticConfiguration); err != nil {
|
||||
log.WithoutContext().Debug(err)
|
||||
log.Debug().Err(err).Send()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
)
|
||||
|
||||
// FooCert is a PEM-encoded TLS cert.
|
||||
@ -94,7 +95,6 @@ func TestAppendCertMetric(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -114,3 +114,73 @@ func TestAppendCertMetric(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDefaultsEntrypoints(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
entrypoints static.EntryPoints
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
desc: "Skips special names",
|
||||
entrypoints: map[string]*static.EntryPoint{
|
||||
"web": {
|
||||
Address: ":80",
|
||||
},
|
||||
"traefik": {
|
||||
Address: ":8080",
|
||||
},
|
||||
},
|
||||
expected: []string{"web"},
|
||||
},
|
||||
{
|
||||
desc: "Two EntryPoints not attachable",
|
||||
entrypoints: map[string]*static.EntryPoint{
|
||||
"web": {
|
||||
Address: ":80",
|
||||
},
|
||||
"websecure": {
|
||||
Address: ":443",
|
||||
},
|
||||
},
|
||||
expected: []string{"web", "websecure"},
|
||||
},
|
||||
{
|
||||
desc: "Two EntryPoints only one attachable",
|
||||
entrypoints: map[string]*static.EntryPoint{
|
||||
"web": {
|
||||
Address: ":80",
|
||||
},
|
||||
"websecure": {
|
||||
Address: ":443",
|
||||
AsDefault: true,
|
||||
},
|
||||
},
|
||||
expected: []string{"websecure"},
|
||||
},
|
||||
{
|
||||
desc: "Two attachable EntryPoints",
|
||||
entrypoints: map[string]*static.EntryPoint{
|
||||
"web": {
|
||||
Address: ":80",
|
||||
AsDefault: true,
|
||||
},
|
||||
"websecure": {
|
||||
Address: ":443",
|
||||
AsDefault: true,
|
||||
},
|
||||
},
|
||||
expected: []string{"web", "websecure"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
actual := getDefaultsEntrypoints(&static.Configuration{
|
||||
EntryPoints: test.entrypoints,
|
||||
})
|
||||
|
||||
assert.ElementsMatch(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/traefik/paerser/cli"
|
||||
"github.com/traefik/traefik/v2/pkg/version"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
)
|
||||
|
||||
var versionTemplate = `Version: {{.Version}}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
FROM alpine:3.14
|
||||
# Feel free to add below any helpful dependency for debugging.
|
||||
# iproute2 is for ss.
|
||||
RUN apk --no-cache --no-progress add bash curl ca-certificates tzdata lsof iproute2 \
|
||||
&& update-ca-certificates \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
COPY dist/traefik /
|
||||
EXPOSE 80
|
||||
VOLUME ["/tmp"]
|
||||
ENTRYPOINT ["/traefik"]
|
@ -1,7 +1,8 @@
|
||||
FROM alpine:3.14 as alpine
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk --no-cache --no-progress add \
|
||||
build-base \
|
||||
gcompat \
|
||||
libcurl \
|
||||
libxml2-dev \
|
||||
libxslt-dev \
|
||||
@ -13,8 +14,8 @@ RUN apk --no-cache --no-progress add \
|
||||
ruby-json \
|
||||
zlib-dev
|
||||
|
||||
RUN gem install nokogiri --version 1.13.3 --no-document -- --use-system-libraries
|
||||
RUN gem install html-proofer --version 3.19.3 --no-document -- --use-system-libraries
|
||||
RUN gem install nokogiri --version 1.16.8 --no-document -- --use-system-libraries
|
||||
RUN gem install html-proofer --version 5.0.7 --no-document -- --use-system-libraries
|
||||
|
||||
# After Ruby, some NodeJS YAY!
|
||||
RUN apk --no-cache --no-progress add \
|
||||
@ -22,12 +23,9 @@ RUN apk --no-cache --no-progress add \
|
||||
nodejs \
|
||||
npm
|
||||
|
||||
# To handle 'not get uid/gid'
|
||||
RUN npm config set unsafe-perm true
|
||||
|
||||
RUN npm install --global \
|
||||
markdownlint@0.22.0 \
|
||||
markdownlint-cli@0.26.0
|
||||
markdownlint@0.29.0 \
|
||||
markdownlint-cli@0.35.0
|
||||
|
||||
# Finally the shell tools we need for later
|
||||
# tini helps to terminate properly all the parallelized tasks when sending CTRL-C
|
||||
|
BIN
docs/content/assets/img/traefik.logo-dark.png
Normal file
BIN
docs/content/assets/img/traefik.logo-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
@ -1,14 +1,14 @@
|
||||
---
|
||||
title: "Traefik Advocation Documentation"
|
||||
description: "There are many ways to contribute to Traefik Proxy. If you're talking about Traefik, let us know and we'll promote your enthusiasm!"
|
||||
description: "There are many ways to contribute to Traefik Proxy. Let us know if you’re talking about Traefik, and we'll promote your enthusiasm!"
|
||||
---
|
||||
|
||||
# Advocating
|
||||
|
||||
Spread the Love & Tell Us about It
|
||||
Spread the Love & Tell Us About It
|
||||
{: .subtitle }
|
||||
|
||||
Traefik Proxy was started by the community for the community.
|
||||
Traefik Proxy was started by the community and for the community.
|
||||
You can contribute to the Traefik community in three main ways:
|
||||
|
||||
**Spread the word!** Guides, videos, blog posts, how-to articles, and showing off your network design all help spread the word about Traefik Proxy
|
||||
|
@ -13,67 +13,13 @@ Let's see how.
|
||||
|
||||
## Building
|
||||
|
||||
You need either [Docker](https://github.com/docker/docker "Link to website of Docker") and `make` (Method 1), or [Go](https://go.dev/ "Link to website of 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.
|
||||
|
||||
```bash
|
||||
make binary
|
||||
```
|
||||
|
||||
This will create binaries for the Linux platform in the `dist` folder.
|
||||
|
||||
In case when you run build on CI, you may probably want to run docker in non-interactive mode. To achieve that define `DOCKER_NON_INTERACTIVE=true` environment variable.
|
||||
|
||||
```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.16-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/traefik/traefik/"dist":/go/src/github.com/traefik/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 `IN_DOCKER` to an empty string (although be aware that some of the tests might fail in that context):
|
||||
|
||||
- `test-unit`
|
||||
- `test-integration`
|
||||
- `validate`
|
||||
- `binary` (the webUI is still generated by using Docker)
|
||||
|
||||
ex:
|
||||
|
||||
```bash
|
||||
IN_DOCKER= make test-unit
|
||||
```
|
||||
|
||||
### Method 2: Using `go`
|
||||
|
||||
Requirements:
|
||||
|
||||
- `go` v1.16+
|
||||
- environment variable `GO111MODULE=on`
|
||||
You need:
|
||||
- [Docker](https://github.com/docker/docker "Link to website of Docker")
|
||||
- `make`
|
||||
- [Go](https://go.dev/ "Link to website of Go")
|
||||
- [misspell](https://github.com/golangci/misspell)
|
||||
- [shellcheck](https://github.com/koalaman/shellcheck)
|
||||
- [Tailscale](https://tailscale.com/) if you are using Docker Desktop
|
||||
|
||||
!!! tip "Source Directory"
|
||||
|
||||
@ -106,43 +52,34 @@ Requirements:
|
||||
## ... and the list goes on
|
||||
```
|
||||
|
||||
#### Build Traefik
|
||||
### Build Traefik
|
||||
|
||||
Once you've set up your go environment and cloned the source repository, you can build Traefik.
|
||||
|
||||
```bash
|
||||
# Generate UI static files
|
||||
make clean-webui generate-webui
|
||||
$ make binary
|
||||
SHA: 8fddfe118288bb5280eb5e77fa952f52def360b4 cheddar 2024-01-11_03:14:57PM
|
||||
CGO_ENABLED=0 GOGC=off GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w \
|
||||
-X github.com/traefik/traefik/v2/pkg/version.Version=8fddfe118288bb5280eb5e77fa952f52def360b4 \
|
||||
-X github.com/traefik/traefik/v2/pkg/version.Codename=cheddar \
|
||||
-X github.com/traefik/traefik/v2/pkg/version.BuildDate=2024-01-11_03:14:57PM" \
|
||||
-installsuffix nocgo -o "./dist/darwin/arm64/traefik" ./cmd/traefik
|
||||
|
||||
# required to merge non-code components into the final binary,
|
||||
# such as the web dashboard/UI
|
||||
go generate
|
||||
$ ls dist/
|
||||
traefik*
|
||||
```
|
||||
|
||||
```bash
|
||||
# Standard go build
|
||||
go build ./cmd/traefik
|
||||
```
|
||||
|
||||
You will find the Traefik executable (`traefik`) in the `~/go/src/github.com/traefik/traefik` directory.
|
||||
You will find the Traefik executable (`traefik`) in the `./dist` directory.
|
||||
|
||||
## 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/traefik/traefik/dist:/go/src/github.com/traefik/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 .)
|
||||
GOOS=darwin GOARCH=arm64 go test -cover "-coverprofile=cover.out" -v ./pkg/... ./cmd/...
|
||||
+ go test -cover -coverprofile=cover.out .
|
||||
ok github.com/traefik/traefik 0.005s coverage: 4.1% of statements
|
||||
|
||||
@ -151,28 +88,30 @@ Test success
|
||||
|
||||
For development purposes, you can specify which tests to run by using (only works the `test-integration` target):
|
||||
|
||||
??? note "Configuring Tailscale for Docker Desktop user"
|
||||
|
||||
Create `tailscale.secret` file in `integration` directory.
|
||||
|
||||
This file needs to contain a [Tailscale auth key](https://tailscale.com/kb/1085/auth-keys)
|
||||
(an ephemeral, but reusable, one is recommended).
|
||||
|
||||
Add this section to your tailscale ACLs to auto-approve the routes for the
|
||||
containers in the docker subnet:
|
||||
|
||||
```json
|
||||
"autoApprovers": {
|
||||
// Allow myself to automatically
|
||||
// advertize routes for docker networks
|
||||
"routes": {
|
||||
"172.31.42.0/24": ["your_tailscale_identity"],
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
```bash
|
||||
# Run every tests in the MyTest suite
|
||||
TESTFLAGS="-check.f MyTestSuite" make test-integration
|
||||
TESTFLAGS="-test.run TestAccessLogSuite" 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
|
||||
TESTFLAGS="-test.run TestAccessLogSuite -testify.m ^TestAccessLog$" make test-integration
|
||||
```
|
||||
|
||||
Check [gocheck](https://labix.org/gocheck "Link to website of gocheck") for more information.
|
||||
|
||||
### 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/traefik/traefik 0.004s
|
||||
```
|
||||
|
||||
Integration tests must be run from the `integration/` directory and require the `-integration` switch: `$ cd integration && go test -integration ./...`.
|
||||
|
@ -66,7 +66,6 @@ providers:
|
||||
docker:
|
||||
endpoint: "tcp://10.10.10.10:2375"
|
||||
exposedByDefault: true
|
||||
swarmMode: true
|
||||
|
||||
tls:
|
||||
ca: dockerCA
|
||||
@ -86,7 +85,6 @@ providers:
|
||||
docker:
|
||||
endpoint: "xxxx"
|
||||
exposedByDefault: true
|
||||
swarmMode: true
|
||||
|
||||
tls:
|
||||
ca: xxxx
|
||||
|
@ -15,13 +15,13 @@ Let's see how.
|
||||
|
||||
### General
|
||||
|
||||
This [documentation](https://doc.traefik.io/traefik/ "Link to the official Traefik documentation") is built with [MkDocs](https://mkdocs.org/ "Link to website of MkDocs").
|
||||
This [documentation](../../ "Link to the official Traefik documentation") is built with [MkDocs](https://mkdocs.org/ "Link to the website of MkDocs").
|
||||
|
||||
### Method 1: `Docker` and `make`
|
||||
|
||||
Please make sure you have the following requirements installed:
|
||||
|
||||
- [Docker](https://www.docker.com/ "Link to website of Docker")
|
||||
- [Docker](https://www.docker.com/ "Link to the website of Docker")
|
||||
|
||||
You can build the documentation and test it locally (with live reloading), using the `docs-serve` target:
|
||||
|
||||
@ -51,7 +51,7 @@ $ make docs-build
|
||||
|
||||
Please make sure you have the following requirements installed:
|
||||
|
||||
- [Python](https://www.python.org/ "Link to website of Python")
|
||||
- [Python](https://www.python.org/ "Link to the website of Python")
|
||||
- [pip](https://pypi.org/project/pip/ "Link to the website of pip on PyPI")
|
||||
|
||||
```bash
|
||||
|
@ -7,89 +7,75 @@ description: "Interested in contributing more to the community and becoming a Tr
|
||||
|
||||

|
||||
|
||||
Note: the document is a work in progress.
|
||||
|
||||
Welcome to the Traefik Community.
|
||||
This document describes how to be part of the core team
|
||||
together with various responsibilities
|
||||
and guidelines for Traefik maintainers.
|
||||
|
||||
We are strongly promoting a philosophy of openness and sharing,
|
||||
and firmly standing against the elitist closed approach.
|
||||
Being part of the core team should be accessible to anyone motivated
|
||||
and wants to be part of that journey!
|
||||
|
||||
## Onboarding Process
|
||||
## Becoming a Maintainer
|
||||
|
||||
If you consider joining our community, please drop us a line using Twitter or leave a note in the issue.
|
||||
We will schedule a quick call to meet you and learn more about your motivation.
|
||||
During the call, the team will discuss the process of becoming a maintainer.
|
||||
We will be happy to answer any questions and explain all your doubts.
|
||||
Before a contributor becomes a maintainer, they should meet the following requirements:
|
||||
|
||||
## Maintainer's Requirements
|
||||
- The contributor enabled [2FA](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) on their GitHub account
|
||||
|
||||
Note: you do not have to meet all the listed requirements,
|
||||
but must have achieved several.
|
||||
- The contributor showed a consistent pattern of helpful, non-threatening, and friendly behavior towards other community members in the past.
|
||||
|
||||
- The contributor has read and accepted the maintainer's guidelines.
|
||||
|
||||
The contributor should also meet one or several of the following requirements:
|
||||
|
||||
- Enabled [2FA](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) on your GitHub account
|
||||
- The contributor has opened and successfully run medium to large PR’s in the past 6 months.
|
||||
|
||||
- The contributor has participated in multiple code reviews of other PR’s,
|
||||
including those of other maintainers and contributors.
|
||||
- The contributor showed a consistent pattern of helpful, non-threatening, and friendly behavior towards other community members in the past.
|
||||
|
||||
- The contributor is active on Traefik Community forums
|
||||
or other technical forums/boards such as K8S slack, Reddit, StackOverflow, hacker news.
|
||||
- Have read and accepted the contributor guidelines.
|
||||
or other technical forums/boards, such as K8S Slack, Reddit, StackOverflow, and Hacker News.
|
||||
|
||||
Any existing active maintainer can create an issue to discuss promoting a contributor to maintainer.
|
||||
Other maintainers can vote on the issue, and if the quorum is reached, the contributor is promoted to maintainer.
|
||||
If the quorum is not reached within one month after the issue is created, it is closed.
|
||||
|
||||
## Maintainer's Responsibilities and Privileges
|
||||
|
||||
There are lots of areas where you can contribute to the project,
|
||||
but we can suggest you start with activities such as:
|
||||
As a maintainer, you are granted a vote for the following:
|
||||
|
||||
- PR reviewing.
|
||||
- According to our guidelines we require you have at least 3 reviewers,
|
||||
thus you can review a PR and leave the relevant comment if it is necessary.
|
||||
- Participating in a daily [issue triage](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md).
|
||||
- The process helps to understand and prioritize the reported issue according to its importance and severity.
|
||||
This is crucial to learn how our users implement Traefik.
|
||||
Each of the issues that are labeled as bug/possible bug/confirmed requires a reproducible use case.
|
||||
You can help in creating a reproducible use case if it has not been added to the issue
|
||||
or use the sample code provided by the reporter.
|
||||
Typically, a simple Docker Compose should be enough to reproduce the issue.
|
||||
- Code contribution.
|
||||
- Documentation contribution.
|
||||
- Technical documentation is one of the most important components of the product.
|
||||
The ability to set up a testing environment in a few minutes,
|
||||
using the official documentation,
|
||||
is a game changer.
|
||||
- You will be listed on our Maintainers GitHub page
|
||||
and on our website in the section [maintainers](maintainers.md).
|
||||
- We will be promoting you on social channels (mostly on Twitter).
|
||||
- [PR review](https://github.com/traefik/contributors-guide/blob/master/pr_guidelines.md).
|
||||
|
||||
## Governance
|
||||
- [Design review](https://github.com/traefik/contributors-guide/blob/master/proposals.md).
|
||||
|
||||
- Roadmap meetings on a regular basis where all maintainers are welcome.
|
||||
- [Proposals](https://github.com/traefik/contributors-guide/blob/master/proposals.md).
|
||||
|
||||
Maintainers are also added to the maintainer's Discord server where happens the [issue triage](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md)
|
||||
and appear on the [Maintainers](maintainers.md) page.
|
||||
|
||||
As a maintainer, you should:
|
||||
|
||||
- Prioritize PR reviews, design reviews, and issue triage above any other task.
|
||||
|
||||
Making sure contributors and community members are listened to and have an impact on the project is essential to keeping the project active and develop a thriving community.
|
||||
|
||||
- Prioritize helping contributors reaching the expecting quality level over rewriting contributions.
|
||||
|
||||
Any triage activity on issues and PRs (e.g. labels, marking messages as off-topic, refusing, marking duplicates) should result from a collective decision to ensure knowledge is shared among maintainers.
|
||||
|
||||
## Communicating
|
||||
|
||||
- All of our maintainers are added to Slack #traefik-maintainers channel that belongs to Traefik labs workspace.
|
||||
- All of our maintainers are added to the Traefik Maintainers Discord server that belongs to Traefik labs.
|
||||
Having the team in one place helps us to communicate effectively.
|
||||
You can reach Traefik core developers directly,
|
||||
which offers the possibility to discuss issues, pull requests, enhancements more efficiently
|
||||
Maintainers can discuss issues, pull requests, enhancements more efficiently
|
||||
and get the feedback almost immediately.
|
||||
Fewer blockers mean more fun and engaging work.
|
||||
|
||||
- On a daily basis, we publish a report that includes all the activities performed during the day.
|
||||
You are updated in regard to the workload that has been processed including:
|
||||
working on the new features and enhancements,
|
||||
activities related to the reported issues and PR’s,
|
||||
other important project-related announcements.
|
||||
- Every decision made on the discord server among maintainers is documented so it's visible to the rest of the community.
|
||||
|
||||
- At 5:00 PM CET every day we review all the created issues that have been reported,
|
||||
assign them the appropriate *[labels](maintainers.md#labels)*
|
||||
and prioritize them based on the severity of the problem.
|
||||
The process is called *[issue triaging](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md)*.
|
||||
Each of the maintainers is welcome to join the meeting.
|
||||
For that purpose, we use a dedicated Discord server
|
||||
where you are invited once you have become the official maintainer.
|
||||
- Maintainers express their opinions on issues and reviews.
|
||||
It is fine to have different point of views.
|
||||
We encourage active and open conversations which goals are to improve Traefik.
|
||||
|
||||
- When discussing issues and proposals, maintainers should share as much information as possible to help solve the issue.
|
||||
|
||||
## Maintainers Activity
|
||||
|
||||
@ -97,38 +83,45 @@ In order to keep the core team efficient and dynamic,
|
||||
maintainers' activity and involvement will be reviewed on a regular basis.
|
||||
|
||||
- Has the maintainer engaged with the team and the community by meeting two or more of these benchmarks in the past six months?
|
||||
|
||||
- Has the maintainer participated in at least two or three maintainer meetings?
|
||||
|
||||
- Substantial review of at least one or two PRs from either contributors or maintainers.
|
||||
|
||||
- Opened at least one or two bug fixes or feature request PRs
|
||||
that were eventually merged (or on a trajectory for merge).
|
||||
|
||||
- Substantial participation in the Help Wanted program (answered questions, helped identify issues, applied guidelines from the Help Wanted guide to open issues).
|
||||
|
||||
- Substantial participation with the community in general.
|
||||
|
||||
- Has the maintainer shown a consistent pattern of helpful,
|
||||
non-threatening,
|
||||
and friendly behavior towards other people on the maintainer team and with our community?
|
||||
|
||||
## Additional Comments for (not only) Maintainers
|
||||
## Additional Comments for Maintainers (that should apply to any contributor)
|
||||
|
||||
- Be respectful with other maintainers and other community members.
|
||||
|
||||
- Be open minded when participating in conversations: try to put yourself in others’ shoes.
|
||||
|
||||
- Be able to put yourself in users’ shoes.
|
||||
- Be open-minded and respectful with other maintainers and other community members.
|
||||
- Keep the communication public -
|
||||
if anyone tries to communicate with you directly,
|
||||
ask politely to move the conversation to a public communication channel.
|
||||
|
||||
- Stay away from defensive comments.
|
||||
|
||||
- Please try to express your thoughts clearly enough
|
||||
and note that some of us are not native English speakers.
|
||||
Try to rephrase your sentences, avoiding mental shortcuts;
|
||||
none of us is able to predict your thoughts.
|
||||
- There are a lot of use cases of using Traefik
|
||||
and even more issues that are difficult to reproduce.
|
||||
If the issue can’t be replicated due to a lack of reproducible case (a simple Docker Compose should be enough) -
|
||||
set your time limits while working on the issue
|
||||
and express clearly that you were not able to replicate it.
|
||||
You can come back later to that case.
|
||||
none of us is able to predict anyone's thoughts.
|
||||
|
||||
- Be proactive.
|
||||
|
||||
- Emoji are fine,
|
||||
but if you express yourself clearly enough they are not necessary.
|
||||
They will not replace good communication.
|
||||
- Embrace mentorship.
|
||||
- Keep in mind that we all have the same intent to improve the project.
|
||||
|
||||
- Embrace mentorship: help others grow and match the quality level we strive for.
|
||||
|
||||
- Keep in mind that we all have the same goal: improve the project.
|
||||
|
@ -5,18 +5,12 @@ description: "Traefik Proxy is an open source software with a thriving community
|
||||
|
||||
# Maintainers
|
||||
|
||||
## The Team
|
||||
## Active Maintainers
|
||||
|
||||
* 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 [@mjantke](https://github.com/mjeri)
|
||||
* 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)
|
||||
@ -25,109 +19,22 @@ description: "Traefik Proxy is an open source software with a thriving community
|
||||
* Kevin Pollet [@kevinpollet](https://github.com/kevinpollet)
|
||||
* Harold Ozouf [@jspdown](https://github.com/jspdown)
|
||||
* Tom Moulard [@tommoulard](https://github.com/tommoulard)
|
||||
* Landry Benguigui [@lbenguigui](https://github.com/lbenguigui)
|
||||
* Simon Delicata [@sdelicata](https://github.com/sdelicata)
|
||||
* Baptiste Mayelle [@youkoulayley](https://github.com/youkoulayley)
|
||||
* Jesper Noordsij [@jnoordsij](https://github.com/jnoordsij)
|
||||
|
||||
## Past Maintainers
|
||||
|
||||
People who have had an incredibly positive impact on the project, and are now focusing on other projects.
|
||||
|
||||
* Vincent Demeester [@vdemeester](https://github.com/vdemeester)
|
||||
* Ed Robinson [@errm](https://github.com/errm)
|
||||
* Daniel Tomcej [@dtomcej](https://github.com/dtomcej)
|
||||
* Timo Reimann [@timoreimann](https://github.com/timoreimann)
|
||||
* Marco Jantke [@mjantke](https://github.com/mjeri)
|
||||
* Ludovic Fernandez [@ldez](https://github.com/ldez)
|
||||
|
||||
## Maintainer's Guidelines
|
||||
|
||||
Please read the [maintainer's guidelines](maintainers-guidelines.md)
|
||||
|
||||
## Issue Triage
|
||||
|
||||
Issues and PRs are triaged daily and the process for triaging may be found under [triaging issues](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md) in our [contributors guide repository](https://github.com/traefik/contributors-guide).
|
||||
|
||||
## PR Review Process
|
||||
|
||||
The process for reviewing PRs may be found under [review guidelines](https://github.com/traefik/contributors-guide/blob/master/review_guidelines.md) in our contributors guide repository.
|
||||
|
||||
## 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.
|
||||
Please read the [maintainer's guidelines](maintainers-guidelines.md).
|
||||
|
@ -11,8 +11,8 @@ Help Us Help You!
|
||||
Issues are perfect for requesting a feature/enhancement or reporting a suspected bug.
|
||||
We use the [GitHub issue tracker](https://github.com/traefik/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 help us (and other community members) quickly and effortlessly understand what you need,
|
||||
The process of sorting and checking the issues is a daunting task, and requires a lot of work.
|
||||
To help maintainers (and other community members) quickly and effortlessly understand what you need,
|
||||
be sure to follow the guidelines below.
|
||||
|
||||
!!! important "Getting Help Vs Reporting an Issue"
|
||||
|
@ -17,12 +17,9 @@ or the list of [confirmed bugs](https://github.com/traefik/traefik/labels/kind%2
|
||||
|
||||
## How We Prioritize
|
||||
|
||||
We wish we could review every pull request right away.
|
||||
Unfortunately, our team has to prioritize pull requests (PRs) for review
|
||||
(but we are welcoming new [maintainers](https://github.com/traefik/traefik/blob/master/docs/content/contributing/maintainers-guidelines.md) to speed this up,
|
||||
if you are interested, check it out and apply).
|
||||
We wish we could review every pull request right away, but because it's a time-consuming operation, it's not always possible.
|
||||
|
||||
The PRs we are able to handle fastest are:
|
||||
The PRs we are able to handle the fastest are:
|
||||
|
||||
* Documentation updates.
|
||||
* Bug fixes.
|
||||
@ -57,9 +54,10 @@ Merging a PR requires the following steps to be completed before it is merged au
|
||||
* Keep "allows edit from maintainer" checked.
|
||||
* Use semantic line breaks for documentation.
|
||||
* Ensure your PR is not a draft. We do not review drafts, but do answer questions and confer with developers on them as needed.
|
||||
* Ensure that the dependencies in the `go.mod` file reference a tag. If referencing a tag is not possible, add a comment explaining why.
|
||||
* Pass the validation check.
|
||||
* Pass all tests.
|
||||
* Receive 3 approving reviews maintainers.
|
||||
* Receive 2 approving reviews from maintainers.
|
||||
|
||||
## Pull Request Review Cycle
|
||||
|
||||
@ -92,6 +90,9 @@ in short, it looks like this:
|
||||
You must run these local verifications before you submit your pull request to predict the pass or failure of continuous integration.
|
||||
Your PR will not be reviewed until these are green on the CI.
|
||||
|
||||
* `make generate`
|
||||
* `make generate-crd`
|
||||
* `make test-gateway-api-conformance`
|
||||
* `make validate`
|
||||
* `make pull-images`
|
||||
* `make test`
|
||||
@ -115,7 +116,7 @@ In such a situation, solve the conflicts/CI/... and then remove the label `bot/n
|
||||
|
||||
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.
|
||||
The label `bot/light-review` decreases the number of required LGTM from 2 to 1.
|
||||
|
||||
This label can be used when:
|
||||
|
||||
@ -129,7 +130,7 @@ This label can be used when:
|
||||
Traefik Proxy is made by the community for the community,
|
||||
as such the goal is to engage the community to make Traefik the best reverse proxy available.
|
||||
Part of this goal is maintaining a lean codebase and ensuring code velocity.
|
||||
unfortunately, this means that sometimes we will not be able to merge a pull request.
|
||||
Unfortunately, this means that sometimes we will not be able to merge a pull request.
|
||||
|
||||
Because we respect the work you did, you will always be told why we are closing your pull request.
|
||||
If you do not agree with our decision, do not worry; closed pull requests are effortless to recreate,
|
||||
@ -198,7 +199,7 @@ here are some things you can do to move the process along:
|
||||
* If you have fixed all the issues from a review,
|
||||
remember to re-request a review (using the designated button) to let your reviewer know that you are ready.
|
||||
You can choose to comment with the changes you made.
|
||||
* Ping `@tfny` if you have not been assigned to a reviewer.
|
||||
* Kindly comment on the pull request. Doing so will automatically give your PR visibility during the triage process.
|
||||
|
||||
For more information on best practices, try these links:
|
||||
|
||||
|
@ -8,7 +8,7 @@ description: "Security is a key part of Traefik Proxy. Read the technical docume
|
||||
## Security Advisories
|
||||
|
||||
We strongly advise you to join our mailing list to be aware of the latest announcements from our security team.
|
||||
You can subscribe sending a mail to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
You can subscribe by sending an email to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
|
||||
|
||||
## CVE
|
||||
|
||||
@ -18,4 +18,6 @@ Reported vulnerabilities can be found on
|
||||
## Report a Vulnerability
|
||||
|
||||
We want to keep Traefik safe for everyone.
|
||||
If you've discovered a security vulnerability in Traefik, we appreciate your help in disclosing it to us in a responsible manner, using [this form](https://security.traefik.io).
|
||||
If you've discovered a security vulnerability in Traefik,
|
||||
we appreciate your help in disclosing it to us in a responsible manner,
|
||||
by creating a [security advisory](https://github.com/traefik/traefik/security/advisories).
|
||||
|
@ -9,7 +9,7 @@ _You_ Made It
|
||||
{: .subtitle}
|
||||
|
||||
Traefik Proxy truly is an [open-source project](https://github.com/traefik/traefik/),
|
||||
and wouldn't have become what it is today without the help of our [many contributors](https://github.com/traefik/traefik/graphs/contributors) (at the time of writing this),
|
||||
and wouldn't have become what it is today without the help of our [many contributors](https://github.com/traefik/traefik/graphs/contributors),
|
||||
not accounting for people having helped with issues, tests, comments, articles, ... or just enjoy using Traefik Proxy and share with others.
|
||||
|
||||
So once again, thank you for your invaluable help in making Traefik such a good product!
|
||||
@ -17,16 +17,16 @@ So once again, thank you for your invaluable help in making Traefik such a good
|
||||
!!! 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).
|
||||
- Propose an idea, request a feature, or report a bug,
|
||||
then read [Submitting Issues](./submitting-issues.md).
|
||||
- Discover how to make an efficient contribution,
|
||||
read the page [Submitting Pull Requests](./submitting-pull-requests.md).
|
||||
then read [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.
|
||||
then the page [Building and Testing](./building-testing.md) is for you.
|
||||
- Contribute to the documentation,
|
||||
read the related page [Documentation](./documentation.md).
|
||||
then read the page about [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.
|
||||
read the [Maintainers](./maintainers.md) and [Maintainer Guidelines](./maintainers-guidelines.md) pages.
|
||||
|
@ -2,43 +2,19 @@
|
||||
|
||||
This page is maintained and updated periodically to reflect our roadmap and any decisions around feature deprecation.
|
||||
|
||||
| Feature | Deprecated | End of Support | Removal |
|
||||
|-----------------------------------------------------------------------------------------------------|------------|----------------|---------|
|
||||
| [Pilot](#pilot) | 2.7 | 2.8 | 2.9 |
|
||||
| [Consul Enterprise Namespace](#consul-enterprise-namespace) | 2.8 | N/A | 3.0 |
|
||||
| [TLS 1.0 and 1.1 Support](#tls-10-and-11) | N/A | 2.8 | N/A |
|
||||
| [Nomad Namespace](#nomad-namespace) | 2.10 | N/A | 3.0 |
|
||||
| [Kubernetes CRDs API Group `traefik.containo.us`](#kubernetes-crds-api-group-traefikcontainous) | 2.10 | N/A | 3.0 |
|
||||
| [Kubernetes CRDs API Version `traefik.io/v1alpha1`](#kubernetes-crds-api-version-traefikiov1alpha1) | N/A | N/A | 3.0 |
|
||||
| Feature | Deprecated | End of Support | Removal |
|
||||
|----------------------------------------------------------------------------------------------------------------------|------------|----------------|---------|
|
||||
| [Kubernetes Ingress API Version `networking.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
||||
| [CRD API Version `apiextensions.k8s.io/v1beta1`](#kubernetes-ingress-api-version-networkingk8siov1beta1) | N/A | N/A | 3.0 |
|
||||
|
||||
## Impact
|
||||
|
||||
### Pilot
|
||||
### Kubernetes Ingress API Version `networking.k8s.io/v1beta1`
|
||||
|
||||
Metrics will continue to function normally up to 2.8, when they will be disabled.
|
||||
In 2.9, the Pilot platform and all Traefik integration code will be permanently removed.
|
||||
The Kubernetes Ingress API Version `networking.k8s.io/v1beta1` support is removed in v3.
|
||||
Please use the API Group `networking.k8s.io/v1` instead.
|
||||
|
||||
Starting on 2.7 the pilot token will not be a requirement anymore for plugins.
|
||||
Since 2.8, a [new plugin catalog](https://plugins.traefik.io) is available, decoupled from Pilot.
|
||||
### Traefik CRD Definitions API Version `apiextensions.k8s.io/v1beta1`
|
||||
|
||||
### Consul Enterprise Namespace
|
||||
|
||||
Starting on 2.8 the `namespace` option of Consul and Consul Catalog providers is deprecated,
|
||||
please use the `namespaces` options instead.
|
||||
|
||||
### TLS 1.0 and 1.1
|
||||
|
||||
Starting on 2.8 the default TLS options will use the minimum version of TLS 1.2. Of course, it can still be overridden with custom configuration.
|
||||
|
||||
### Nomad Namespace
|
||||
|
||||
Starting on 2.10 the `namespace` option of the Nomad provider is deprecated,
|
||||
please use the `namespaces` options instead.
|
||||
|
||||
### Kubernetes CRDs API Group `traefik.containo.us`
|
||||
|
||||
In v2.10, the Kubernetes CRDs API Group `traefik.containo.us` is deprecated, and its support will end starting with Traefik v3. Please use the API Group `traefik.io` instead.
|
||||
|
||||
### Kubernetes CRDs API Version `traefik.io/v1alpha1`
|
||||
|
||||
The newly introduced Kubernetes CRD API Version `traefik.io/v1alpha1` will subsequently be removed in Traefik v3. The following version will be `traefik.io/v1`.
|
||||
The Traefik CRD definitions API Version `apiextensions.k8s.io/v1beta1` support is removed in v3.
|
||||
Please use the API Group `apiextensions.k8s.io/v1` instead.
|
||||
|
@ -4,28 +4,29 @@
|
||||
|
||||
Below is a non-exhaustive list of versions and their maintenance status:
|
||||
|
||||
| Version | Release Date | Active Support | Security Support |
|
||||
|---------|--------------|--------------------|------------------|
|
||||
| 2.9 | Oct 03, 2022 | Yes | Yes |
|
||||
| 2.8 | Jun 29, 2022 | Ended Oct 03, 2022 | No |
|
||||
| 2.7 | May 24, 2022 | Ended Jun 29, 2022 | No |
|
||||
| 2.6 | Jan 24, 2022 | Ended May 24, 2022 | No |
|
||||
| 2.5 | Aug 17, 2021 | Ended Jan 24, 2022 | No |
|
||||
| 2.4 | Jan 19, 2021 | Ended Aug 17, 2021 | No |
|
||||
| 2.3 | Sep 23, 2020 | Ended Jan 19, 2021 | No |
|
||||
| 2.2 | Mar 25, 2020 | Ended Sep 23, 2020 | No |
|
||||
| 2.1 | Dec 11, 2019 | Ended Mar 25, 2020 | No |
|
||||
| 2.0 | Sep 16, 2019 | Ended Dec 11, 2019 | No |
|
||||
| 1.7 | Sep 24, 2018 | Ended Dec 31, 2021 | Contact Support |
|
||||
|
||||
??? example "Active Support / Security Support"
|
||||
|
||||
**Active support**: receives any bug fixes.
|
||||
**Security support**: receives only critical bug and security fixes.
|
||||
| Version | Release Date | Community Support |
|
||||
|---------|--------------|--------------------|
|
||||
| 3.3 | Jan 06, 2025 | Yes |
|
||||
| 3.2 | Oct 28, 2024 | Ended Jan 06, 2025 |
|
||||
| 3.1 | Jul 15, 2024 | Ended Oct 28, 2024 |
|
||||
| 3.0 | Apr 29, 2024 | Ended Jul 15, 2024 |
|
||||
| 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 |
|
||||
| 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 |
|
||||
| 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 |
|
||||
| 2.8 | Jun 29, 2022 | Ended Oct 03, 2022 |
|
||||
| 2.7 | May 24, 2022 | Ended Jun 29, 2022 |
|
||||
| 2.6 | Jan 24, 2022 | Ended May 24, 2022 |
|
||||
| 2.5 | Aug 17, 2021 | Ended Jan 24, 2022 |
|
||||
| 2.4 | Jan 19, 2021 | Ended Aug 17, 2021 |
|
||||
| 2.3 | Sep 23, 2020 | Ended Jan 19, 2021 |
|
||||
| 2.2 | Mar 25, 2020 | Ended Sep 23, 2020 |
|
||||
| 2.1 | Dec 11, 2019 | Ended Mar 25, 2020 |
|
||||
| 2.0 | Sep 16, 2019 | Ended Dec 11, 2019 |
|
||||
| 1.7 | Sep 24, 2018 | Ended Dec 31, 2021 |
|
||||
|
||||
This page is maintained and updated periodically to reflect our roadmap and any decisions affecting the end of support for Traefik Proxy.
|
||||
|
||||
Please refer to our migration guides for specific instructions on upgrading between versions, an example is the [v1 to v2 migration guide](../migration/v1-to-v2.md).
|
||||
Please refer to our migration guides for specific instructions on upgrading between versions, an example is the [v2 to v3 migration guide](../migration/v2-to-v3.md).
|
||||
|
||||
!!! important "All target dates for end of support or feature removal announcements may be subject to change."
|
||||
|
||||
|
@ -11,7 +11,7 @@ This page explains the base concepts of Traefik.
|
||||
|
||||
## Introduction
|
||||
|
||||
Traefik is based on the concept of EntryPoints, Routers, Middelwares and Services.
|
||||
Traefik is based on the concept of EntryPoints, Routers, Middlewares and Services.
|
||||
|
||||
The main features include dynamic configuration, automatic service discovery, and support for multiple backends and protocols.
|
||||
|
||||
@ -25,7 +25,7 @@ The main features include dynamic configuration, automatic service discovery, an
|
||||
|
||||
## 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:
|
||||
Traefik is an *Edge Router*; this 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](../routing/routers/index.md#rule "Link to docs about routing rules") that determine which services handle which requests (based on the *path*, the *host*, *headers*, etc.).
|
||||
|
||||

|
||||
@ -38,7 +38,7 @@ Deploying your services, you attach information that tells Traefik the character
|
||||
|
||||

|
||||
|
||||
It means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time.
|
||||
This means that when a service is deployed, Traefik detects it immediately and updates the routing rules in real time.
|
||||
Similarly, when a service is removed from the infrastructure, the corresponding route is deleted accordingly.
|
||||
|
||||
You no longer need to create and synchronize configuration files cluttered with IP addresses or other rules.
|
||||
|
@ -79,14 +79,14 @@ traefik --help
|
||||
# or
|
||||
|
||||
docker run traefik[:version] --help
|
||||
# ex: docker run traefik:v2.10 --help
|
||||
# ex: docker run traefik:v3.3 --help
|
||||
```
|
||||
|
||||
All available arguments can also be found [here](../reference/static-configuration/cli.md).
|
||||
Check the [CLI reference](../reference/static-configuration/cli.md "Link to CLI reference overview") for an overview about all available arguments.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
All available environment variables can be found [here](../reference/static-configuration/env.md)
|
||||
All available environment variables can be found in the [static configuration environment overview](../reference/static-configuration/env.md).
|
||||
|
||||
## Available Configuration Options
|
||||
|
||||
|
@ -29,7 +29,7 @@ Not to mention that dynamic configuration changes potentially make that kind of
|
||||
Therefore, in this dynamic context,
|
||||
the static configuration of an `entryPoint` does not give any hint whatsoever about how the traffic going through that `entryPoint` is going to be routed.
|
||||
Or whether it's even going to be routed at all,
|
||||
i.e. whether there is a Router matching the kind of traffic going through it.
|
||||
that is whether there is a Router matching the kind of traffic going through it.
|
||||
|
||||
### `404 Not found`
|
||||
|
||||
@ -71,7 +71,7 @@ Traefik returns a `502` response code when an error happens while contacting the
|
||||
|
||||
### `503 Service Unavailable`
|
||||
|
||||
Traefik returns a `503` response code when a Router has been matched
|
||||
Traefik returns a `503` response code when a Router has been matched,
|
||||
but there are no servers ready to handle the request.
|
||||
|
||||
This situation is encountered when a service has been explicitly configured without servers,
|
||||
@ -84,7 +84,7 @@ Sometimes, the `404` response code doesn't play well with other parties or servi
|
||||
In these situations, you may want Traefik to always reply with a `503` response code,
|
||||
instead of a `404` response code.
|
||||
|
||||
To achieve this behavior, a simple catchall router,
|
||||
To achieve this behavior, a catchall router,
|
||||
with the lowest possible priority and routing to a service without servers,
|
||||
can handle all the requests when no other router has been matched.
|
||||
|
||||
@ -93,7 +93,7 @@ The example below is a file provider only version (`yaml`) of what this configur
|
||||
```yaml tab="Static configuration"
|
||||
# traefik.yml
|
||||
|
||||
entrypoints:
|
||||
entryPoints:
|
||||
web:
|
||||
address: :80
|
||||
|
||||
@ -130,7 +130,7 @@ http:
|
||||
the principle of the above example above (a catchall router) still stands,
|
||||
but the `unavailable` service should be adapted to fit such a need.
|
||||
|
||||
## Why Is My TLS Certificate Not Reloaded When Its Contents Change?
|
||||
## Why Is My TLS Certificate Not Reloaded When Its Contents Change?
|
||||
|
||||
With the file provider,
|
||||
a configuration update is only triggered when one of the [watched](../providers/file.md#provider-configuration) configuration files is modified.
|
||||
@ -143,20 +143,55 @@ To take into account the new certificate contents, the update of the dynamic con
|
||||
One way to achieve that, is to trigger a file notification,
|
||||
for example, by using the `touch` command on the configuration file.
|
||||
|
||||
## What Are the Forwarded Headers When Proxying HTTP Requests?
|
||||
## How Traefik is Storing and Serving TLS Certificates?
|
||||
|
||||
By default, the following headers are automatically added when proxying requests:
|
||||
### Storing TLS Certificates
|
||||
|
||||
| Property | HTTP Header |
|
||||
|---------------------------|----------------------------|
|
||||
| Client's IP | X-Forwarded-For, X-Real-Ip |
|
||||
| Host | X-Forwarded-Host |
|
||||
| Port | X-Forwarded-Port |
|
||||
| Protocol | X-Forwarded-Proto |
|
||||
| Proxy Server's Hostname | X-Forwarded-Server |
|
||||
[TLS](../https/tls.md "Link to Traefik TLS docs") certificates are either provided directly by the [dynamic configuration](./configuration-overview.md#the-dynamic-configuration "Link to dynamic configuration overview") from [providers](../https/tls.md#user-defined "Link to the TLS configuration"),
|
||||
or by [ACME resolvers](../https/acme.md#providers "Link to ACME resolvers"), which act themselves as providers internally.
|
||||
|
||||
For more details,
|
||||
please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation.
|
||||
For each TLS certificate, Traefik produces an identifier used as a key to store it.
|
||||
This identifier is constructed as the alphabetically ordered concatenation of the SANs `DNSNames` and `IPAddresses` of the TLScertificate.
|
||||
|
||||
#### Examples:
|
||||
|
||||
| X509v3 Subject Alternative Name | TLS Certificate Identifier |
|
||||
|-----------------------------------------|-----------------------------|
|
||||
| `DNS:example.com, IP Address:127.0.0.1` | `127.0.0.1,example.com` |
|
||||
| `DNS:example.com, DNS:*.example.com` | `*.example.com,example.com` |
|
||||
|
||||
The identifier is used to store TLS certificates in order to be later used to handle TLS connections.
|
||||
This operation happens each time there are configuration changes.
|
||||
|
||||
If multiple TLS certificates are provided with the same SANs definition (same identifier), only the one processed first is kept.
|
||||
Because the dynamic configuration is aggregated from all providers,
|
||||
when processing it to gather TLS certificates,
|
||||
there is no guarantee of the order in which they would be processed.
|
||||
This means that along with configurations applied, it is possible that the TLS certificate retained for a given identifier differs.
|
||||
|
||||
### Serving TLS Certificates
|
||||
|
||||
For each incoming connection, Traefik is serving the "best" matching TLS certificate for the provided server name.
|
||||
|
||||
The TLS certificate selection process narrows down the list of TLS certificates matching the server name,
|
||||
and then selects the last TLS certificate in this list after having ordered it by the identifier alphabetically.
|
||||
|
||||
#### Examples:
|
||||
|
||||
| Selected TLS Certificates Identifiers | Sorted TLS Certificates Identifiers | Served Certificate Identifier |
|
||||
|-----------------------------------------------------|-----------------------------------------------------|-------------------------------|
|
||||
| `127.0.0.1,example.com`,`*.example.com,example.com` | `*.example.com,example.com`,`127.0.0.1,example.com` | `127.0.0.1,example.com` |
|
||||
| `*.example.com,example.com`,`example.com` | `*.example.com,example.com`,`example.com` | `example.com` |
|
||||
|
||||
### Caching TLS Certificates
|
||||
|
||||
While Traefik is serving the best matching TLS certificate for each incoming connection,
|
||||
the selection process cost for each incoming connection is avoided thanks to a cache mechanism.
|
||||
|
||||
Once a TLS certificate has been selected as the "best" TLS certificate for a server name,
|
||||
it is cached for an hour, avoiding the selection process for further connections.
|
||||
|
||||
Nonetheless, when a new configuration is applied, the cache is reset.
|
||||
|
||||
## What does the "field not found" error mean?
|
||||
|
||||
@ -166,7 +201,7 @@ error: field not found, node: -badField-
|
||||
|
||||
The "field not found" error occurs, when an unknown property is encountered in the dynamic or static configuration.
|
||||
|
||||
One easy way to check whether a configuration file is well-formed, is to validate it with:
|
||||
One way to check whether a configuration file is well-formed, is to validate it with:
|
||||
|
||||
- [JSON Schema of the static configuration](https://json.schemastore.org/traefik-v2.json)
|
||||
- [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json)
|
||||
@ -176,11 +211,11 @@ One easy way to check whether a configuration file is well-formed, is to validat
|
||||
As a common tip, if a resource is dropped/not created by Traefik after the dynamic configuration was evaluated,
|
||||
one should look for an error in the logs.
|
||||
|
||||
If found, the error obviously confirms that something went wrong while creating the resource,
|
||||
If found, the error confirms that something went wrong while creating the resource,
|
||||
and the message should help in figuring out the mistake(s) in the configuration, and how to fix it.
|
||||
|
||||
When using the file provider,
|
||||
one easy way to check if the dynamic configuration is well-formed is to validate it with the [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json).
|
||||
one way to check if the dynamic configuration is well-formed is to validate it with the [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json).
|
||||
|
||||
## Why does Let's Encrypt wildcard certificate renewal/generation with DNS challenge fail?
|
||||
|
||||
@ -198,6 +233,8 @@ then it could be due to `CNAME` support.
|
||||
In which case, you should make sure your infrastructure is properly set up for a
|
||||
`DNS` challenge that does not rely on `CNAME`, and you should try disabling `CNAME` support with:
|
||||
|
||||
```bash
|
||||
```shell
|
||||
LEGO_DISABLE_CNAME_SUPPORT=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -16,12 +16,12 @@ You can install Traefik with the following flavors:
|
||||
|
||||
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with one sample configuration file:
|
||||
|
||||
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v2.10/traefik.sample.yml)
|
||||
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v2.10/traefik.sample.toml)
|
||||
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v3.3/traefik.sample.yml)
|
||||
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v3.3/traefik.sample.toml)
|
||||
|
||||
```bash
|
||||
```shell
|
||||
docker run -d -p 8080:8080 -p 80:80 \
|
||||
-v $PWD/traefik.yml:/etc/traefik/traefik.yml traefik:v2.10
|
||||
-v $PWD/traefik.yml:/etc/traefik/traefik.yml traefik:v3.3
|
||||
```
|
||||
|
||||
For more details, go to the [Docker provider documentation](../providers/docker.md)
|
||||
@ -29,22 +29,17 @@ For more details, go to the [Docker provider documentation](../providers/docker.
|
||||
!!! tip
|
||||
|
||||
* Prefer a fixed version than the latest that could be an unexpected version.
|
||||
ex: `traefik:v2.10`
|
||||
ex: `traefik:v3.3`
|
||||
* Docker images are based from the [Alpine Linux Official image](https://hub.docker.com/_/alpine).
|
||||
* Any orchestrator using docker images can fetch the official Traefik docker image.
|
||||
|
||||
## Use the Helm Chart
|
||||
|
||||
!!! warning
|
||||
|
||||
The Traefik Chart from
|
||||
[Helm's default charts repository](https://github.com/helm/charts/tree/master/stable/traefik) is still using [Traefik v1.7](https://doc.traefik.io/traefik/v1.7).
|
||||
|
||||
Traefik can be installed in Kubernetes using the Helm chart from <https://github.com/traefik/traefik-helm-chart>.
|
||||
|
||||
Ensure that the following requirements are met:
|
||||
|
||||
* Kubernetes 1.16+
|
||||
* Kubernetes 1.22+
|
||||
* Helm version 3.9+ is [installed](https://helm.sh/docs/intro/install/)
|
||||
|
||||
Add Traefik Labs chart repository to Helm:
|
||||
@ -59,7 +54,7 @@ You can update the chart repository by running:
|
||||
helm repo update
|
||||
```
|
||||
|
||||
And install it with the `helm` command line:
|
||||
And install it with the Helm command line:
|
||||
|
||||
```bash
|
||||
helm install traefik traefik/traefik
|
||||
@ -69,7 +64,7 @@ helm install traefik traefik/traefik
|
||||
|
||||
All [Helm features](https://helm.sh/docs/intro/using_helm/) are supported.
|
||||
|
||||
Examples are provided [here](https://github.com/traefik/traefik-helm-chart/blob/master/EXAMPLES.md).
|
||||
Examples are provided [here](https://github.com/traefik/traefik-helm-chart/blob/master/EXAMPLES.md).
|
||||
|
||||
For instance, installing the chart in a dedicated namespace:
|
||||
|
||||
@ -104,38 +99,6 @@ helm install traefik traefik/traefik
|
||||
- "--log.level=DEBUG"
|
||||
```
|
||||
|
||||
### Exposing the Traefik dashboard
|
||||
|
||||
This HelmChart does not expose the Traefik dashboard by default, for security concerns.
|
||||
Thus, there are multiple ways to expose the dashboard.
|
||||
For instance, the dashboard access could be achieved through a port-forward:
|
||||
|
||||
```shell
|
||||
kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
|
||||
```
|
||||
|
||||
It can then be reached at: `http://127.0.0.1:9000/dashboard/`
|
||||
|
||||
Another way would be to apply your own configuration, for instance,
|
||||
by defining and applying an IngressRoute CRD (`kubectl apply -f dashboard.yaml`):
|
||||
|
||||
```yaml
|
||||
# dashboard.yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: dashboard
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`traefik.localhost`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
```
|
||||
|
||||
## Use the Binary Distribution
|
||||
|
||||
Grab the latest binary from the [releases](https://github.com/traefik/traefik/releases) page.
|
||||
|
@ -1,23 +1,23 @@
|
||||
---
|
||||
title: "Traefik Getting Started With Kubernetes"
|
||||
description: "Looking to get started with Traefik Proxy? Read the technical documentation to learn a simple use case that leverages Kubernetes."
|
||||
description: "Get started with Traefik Proxy and Kubernetes."
|
||||
---
|
||||
|
||||
# Quick Start
|
||||
|
||||
A Simple Use Case of Traefik Proxy and Kubernetes
|
||||
A Use Case of Traefik Proxy and Kubernetes
|
||||
{: .subtitle }
|
||||
|
||||
This guide is an introduction to using Traefik Proxy in a Kubernetes environment.
|
||||
The objective is to learn how to run an application behind a Traefik reverse proxy in Kubernetes.
|
||||
This guide is an introduction to using Traefik Proxy in a Kubernetes environment.
|
||||
The objective is to learn how to run an application behind a Traefik reverse proxy in Kubernetes.
|
||||
It presents and explains the basic blocks required to start with Traefik such as Ingress Controller, Ingresses, Deployments, static, and dynamic configuration.
|
||||
|
||||
## Permissions and Accesses
|
||||
|
||||
Traefik uses the Kubernetes API to discover running services.
|
||||
|
||||
In order to use the Kubernetes API, Traefik needs some permissions.
|
||||
This [permission mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) is based on roles defined by the cluster administrator.
|
||||
To use the Kubernetes API, Traefik needs some permissions.
|
||||
This [permission mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) is based on roles defined by the cluster administrator.
|
||||
The role is then bound to an account used by an application, in this case, Traefik Proxy.
|
||||
|
||||
The first step is to create the role.
|
||||
@ -35,12 +35,19 @@ rules:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
@ -58,6 +65,23 @@ rules:
|
||||
- ingresses/status
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- traefik.io
|
||||
resources:
|
||||
- middlewares
|
||||
- middlewaretcps
|
||||
- ingressroutes
|
||||
- traefikservices
|
||||
- ingressroutetcps
|
||||
- ingressrouteudps
|
||||
- tlsoptions
|
||||
- tlsstores
|
||||
- serverstransports
|
||||
- serverstransporttcps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
```
|
||||
|
||||
!!! info "You can find the reference for this file [there](../../reference/dynamic-configuration/kubernetes-crd/#rbac)."
|
||||
@ -88,7 +112,7 @@ roleRef:
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: traefik-account
|
||||
namespace: default # Using "default" because we did not specify a namespace when creating the ClusterAccount.
|
||||
namespace: default # This tutorial uses the "default" K8s namespace.
|
||||
```
|
||||
|
||||
!!! info "`roleRef` is the Kubernetes reference to the role created in `00-role.yml`."
|
||||
@ -102,7 +126,7 @@ subjects:
|
||||
!!! info "This section can be managed with the help of the [Traefik Helm chart](../install-traefik/#use-the-helm-chart)."
|
||||
|
||||
The [ingress controller](https://traefik.io/glossary/kubernetes-ingress-and-ingress-controller-101/#what-is-a-kubernetes-ingress-controller)
|
||||
is a software that runs in the same way as any other application on a cluster.
|
||||
is a software that runs in the same way as any other application on a cluster.
|
||||
To start Traefik on the Kubernetes cluster,
|
||||
a [`Deployment`](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/deployment-v1/) resource must exist to describe how to configure
|
||||
and scale containers horizontally to support larger workloads.
|
||||
@ -130,7 +154,7 @@ spec:
|
||||
serviceAccountName: traefik-account
|
||||
containers:
|
||||
- name: traefik
|
||||
image: traefik:v2.10
|
||||
image: traefik:v3.3
|
||||
args:
|
||||
- --api.insecure
|
||||
- --providers.kubernetesingress
|
||||
@ -141,12 +165,12 @@ spec:
|
||||
containerPort: 8080
|
||||
```
|
||||
|
||||
The deployment contains an important attribute for customizing Traefik: `args`.
|
||||
These arguments are the static configuration for Traefik.
|
||||
The deployment contains an important attribute for customizing Traefik: `args`.
|
||||
These arguments are the static configuration for Traefik.
|
||||
From here, it is possible to enable the dashboard,
|
||||
configure entry points,
|
||||
select dynamic configuration providers,
|
||||
and [more](../reference/static-configuration/cli.md)...
|
||||
and [more](../reference/static-configuration/cli.md).
|
||||
|
||||
In this deployment,
|
||||
the static configuration enables the Traefik dashboard,
|
||||
@ -159,10 +183,10 @@ and uses Kubernetes native Ingress resources as router definitions to route inco
|
||||
!!! info "When enabling the [`api.insecure`](../../operations/api/#insecure) mode, Traefik exposes the dashboard on the port `8080`."
|
||||
|
||||
A deployment manages scaling and then can create lots of containers, called [Pods](https://kubernetes.io/docs/concepts/workloads/pods/).
|
||||
Each Pod is configured following the `spec` field in the deployment.
|
||||
Each Pod is configured following the `spec` field in the deployment.
|
||||
Given that, a Deployment can run multiple Traefik Proxy Pods,
|
||||
a piece is required to forward the traffic to any of the instance:
|
||||
namely a [`Service`](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#Service).
|
||||
namely a [`Service`](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#Service).
|
||||
Create a file called `02-traefik-services.yml` and insert the two `Service` resources:
|
||||
|
||||
```yaml tab="02-traefik-services.yml"
|
||||
@ -195,7 +219,7 @@ spec:
|
||||
|
||||
!!! warning "It is possible to expose a service in different ways."
|
||||
|
||||
Depending on your working environment and use case, the `spec.type` might change.
|
||||
Depending on your working environment and use case, the `spec.type` might change.
|
||||
It is strongly recommended to understand the available [service types](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) before proceeding to the next step.
|
||||
|
||||
It is now time to apply those files on your cluster to start Traefik.
|
||||
@ -210,11 +234,11 @@ kubectl apply -f 00-role.yml \
|
||||
|
||||
## Proxying applications
|
||||
|
||||
The only part still missing is the business application behind the reverse proxy.
|
||||
The only part still missing is the business application behind the reverse proxy.
|
||||
For this guide, we use the example application [traefik/whoami](https://github.com/traefik/whoami),
|
||||
but the principles are applicable to any other application.
|
||||
|
||||
The `whoami` application is a simple HTTP server running on port 80 which answers host-related information to the incoming requests.
|
||||
The `whoami` application is an HTTP server running on port 80 which answers host-related information to the incoming requests.
|
||||
As usual, start by creating a file called `03-whoami.yml` and paste the following `Deployment` resource:
|
||||
|
||||
```yaml tab="03-whoami.yml"
|
||||
@ -262,8 +286,8 @@ spec:
|
||||
```
|
||||
|
||||
Thanks to the Kubernetes API,
|
||||
Traefik is notified when an Ingress resource is created, updated, or deleted.
|
||||
This makes the process dynamic.
|
||||
Traefik is notified when an Ingress resource is created, updated, or deleted.
|
||||
This makes the process dynamic.
|
||||
The ingresses are, in a way, the [dynamic configuration](../../providers/kubernetes-ingress/) for Traefik.
|
||||
|
||||
!!! tip
|
||||
@ -316,3 +340,5 @@ curl -v http://localhost/
|
||||
- [Filter the ingresses](../providers/kubernetes-ingress.md#ingressclass) to use with [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class)
|
||||
- Use [IngressRoute CRD](../providers/kubernetes-crd.md)
|
||||
- Protect [ingresses with TLS](../routing/providers/kubernetes-ingress.md#enabling-tls-via-annotations)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -1,11 +1,11 @@
|
||||
---
|
||||
title: "Traefik Getting Started Quickly"
|
||||
description: "Looking to get started with Traefik Proxy quickly? Read the technical documentation to learn a simple use case that leverages Docker."
|
||||
description: "Get started with Traefik Proxy and Docker."
|
||||
---
|
||||
|
||||
# Quick Start
|
||||
|
||||
A Simple Use Case Using Docker
|
||||
A Use Case Using Docker
|
||||
{: .subtitle }
|
||||
|
||||

|
||||
@ -19,8 +19,8 @@ version: '3'
|
||||
|
||||
services:
|
||||
reverse-proxy:
|
||||
# The official v2 Traefik docker image
|
||||
image: traefik:v2.10
|
||||
# The official v3 Traefik docker image
|
||||
image: traefik:v3.3
|
||||
# Enables the web UI and tells Traefik to listen to docker
|
||||
command: --api.insecure=true --providers.docker
|
||||
ports:
|
||||
@ -38,14 +38,14 @@ services:
|
||||
Start your `reverse-proxy` with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d reverse-proxy
|
||||
docker compose up -d reverse-proxy
|
||||
```
|
||||
|
||||
You can open a browser and go to `http://localhost:8080/api/rawdata` to see Traefik's API rawdata (we'll go back there once we have launched a service in step 2).
|
||||
You can open a browser and go to `http://localhost:8080/api/rawdata` to see Traefik's API rawdata (you'll go back there once you 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.
|
||||
Now that you have a Traefik instance up and running, you will deploy new services.
|
||||
|
||||
Edit your `docker-compose.yml` file and add the following at the end of your file.
|
||||
|
||||
@ -63,17 +63,17 @@ services:
|
||||
- "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).
|
||||
The above defines `whoami`: a web service that outputs information about the machine it is deployed on (its IP address, host, and others).
|
||||
|
||||
Start the `whoami` service with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d whoami
|
||||
docker compose up -d whoami
|
||||
```
|
||||
|
||||
Go back to your browser (`http://localhost:8080/api/rawdata`) and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||
Browse `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)
|
||||
When Traefik detects new services, it creates the corresponding routes, so you can call them ... _let's see!_ (Here, you're using curl)
|
||||
|
||||
```shell
|
||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||
@ -92,10 +92,10 @@ IP: 172.27.0.3
|
||||
Run more instances of your `whoami` service with the following command:
|
||||
|
||||
```shell
|
||||
docker-compose up -d --scale whoami=2
|
||||
docker compose up -d --scale whoami=2
|
||||
```
|
||||
|
||||
Go back to your browser (`http://localhost:8080/api/rawdata`) and see that Traefik has automatically detected the new instance of the container.
|
||||
Browse to `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:
|
||||
|
||||
@ -103,7 +103,7 @@ Finally, see that Traefik load-balances between the two instances of your servic
|
||||
curl -H Host:whoami.docker.localhost http://127.0.0.1
|
||||
```
|
||||
|
||||
The output will show alternatively one of the followings:
|
||||
The output will show alternatively one of the following:
|
||||
|
||||
```yaml
|
||||
Hostname: a656c8ddca6c
|
||||
@ -119,6 +119,6 @@ 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!
|
||||
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 user guides](../../user-guides/docker-compose/basic-example/ "Link to the user guides") and [the documentation](/ "Link to the docs landing page") and let Traefik work for you!
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -11,7 +11,7 @@ Automatic HTTPS
|
||||
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). These last up to __one week__, and can not be overridden.
|
||||
Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to **one week**, and cannot be overridden.
|
||||
|
||||
When running Traefik in a container this file should be persisted across restarts.
|
||||
If Traefik requests new certificates each time it starts up, a crash-looping container can quickly reach Let's Encrypt's ratelimits.
|
||||
@ -116,8 +116,8 @@ Please check the [configuration examples below](#configuration-examples) for mor
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
@ -241,8 +241,8 @@ when using the `HTTP-01` challenge, `certificatesresolvers.myresolver.acme.httpc
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
```
|
||||
@ -294,6 +294,12 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||
LEGO_DISABLE_CNAME_SUPPORT=true
|
||||
```
|
||||
|
||||
!!! warning "Multiple DNS Challenge provider"
|
||||
|
||||
Multiple DNS challenge provider are not supported with Traefik, but you can use `CNAME` to handle that.
|
||||
For example, if you have `example.org` (account foo) and `example.com` (account bar) you can create a CNAME on `example.org` called `_acme-challenge.example.org` pointing to `challenge.example.com`.
|
||||
This way, you can obtain certificates for `example.org` with the `bar` account.
|
||||
|
||||
!!! important
|
||||
A `provider` is mandatory.
|
||||
|
||||
@ -308,121 +314,156 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
|
||||
|
||||
For complete details, refer to your provider's _Additional configuration_ link.
|
||||
|
||||
| Provider Name | Provider Code | Environment Variables | |
|
||||
|--------------------------------------------------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/acme-dns) |
|
||||
| [Alibaba Cloud](https://www.alibabacloud.com) | `alidns` | `ALICLOUD_ACCESS_KEY`, `ALICLOUD_SECRET_KEY`, `ALICLOUD_REGION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/alidns) |
|
||||
| [all-inkl](https://all-inkl.com) | `allinkl` | `ALL_INKL_LOGIN`, `ALL_INKL_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/allinkl) |
|
||||
| [ArvanCloud](https://www.arvancloud.com/en) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) |
|
||||
| [Auroradns](https://www.pcextreme.com/dns-health-checks) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) |
|
||||
| [Autodns](https://www.internetx.com/domains/autodns/) | `autodns` | `AUTODNS_API_USER`, `AUTODNS_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/autodns) |
|
||||
| [Azure](https://azure.microsoft.com/services/dns/) | `azure` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_METADATA_ENDPOINT]` | [Additional configuration](https://go-acme.github.io/lego/dns/azure) |
|
||||
| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) |
|
||||
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) |
|
||||
| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) |
|
||||
| [Civo](https://www.civo.com/) | `civo` | `CIVO_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/civo) |
|
||||
| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) |
|
||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
|
||||
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
|
||||
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
|
||||
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
|
||||
| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) |
|
||||
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
|
||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
|
||||
| [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) |
|
||||
| [dnsHome.de](https://www.dnshome.de) | `dnsHomede` | `DNSHOMEDE_CREDENTIALS` | [Additional configuration](https://go-acme.github.io/lego/dns/dnshomede) |
|
||||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
|
||||
| [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) |
|
||||
| [Domeneshop](https://domene.shop) | `domeneshop` | `DOMENESHOP_API_TOKEN`, `DOMENESHOP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/domeneshop) |
|
||||
| [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) |
|
||||
| [Dynu](https://www.dynu.com) | `dynu` | `DYNU_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dynu) |
|
||||
| [EasyDNS](https://easydns.com/) | `easydns` | `EASYDNS_TOKEN`, `EASYDNS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/easydns) |
|
||||
| [EdgeDNS](https://www.akamai.com/) | `edgedns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) |
|
||||
| [Epik](https://www.epik.com) | `epik` | `EPIK_SIGNATURE` | [Additional configuration](https://go-acme.github.io/lego/dns/epik) |
|
||||
| [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/edgedns) |
|
||||
| [Freemyip.com](https://freemyip.com) | `freemyip` | `FREEMYIP_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/freemyip) |
|
||||
| [G-Core Lab](https://gcorelabs.com/dns/) | `gcore` | `GCORE_PERMANENT_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/gcore) |
|
||||
| [Gandi v5](https://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandiv5) |
|
||||
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandi) |
|
||||
| [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://www.godaddy.com) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) |
|
||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) |
|
||||
| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) |
|
||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
|
||||
| [Hosttech](https://www.hosttech.eu) | `hosttech` | `HOSTTECH_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hosttech) |
|
||||
| [Hurricane Electric](https://dns.he.net) | `hurricane` | `HURRICANE_TOKENS` [^6] | [Additional configuration](https://go-acme.github.io/lego/dns/hurricane) |
|
||||
| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) |
|
||||
| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) |
|
||||
| [IIJ DNS Platform Service](https://www.iij.ad.jp) | `iijdpf` | `IIJ_DPF_API_TOKEN` , `IIJ_DPF_DPM_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iijdpf) |
|
||||
| [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) |
|
||||
| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USERNAME`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) |
|
||||
| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) |
|
||||
| [Internet.bs](https://internetbs.net) | `internetbs` | `INTERNET_BS_API_KEY`, `INTERNET_BS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/internetbs) |
|
||||
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
|
||||
| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) |
|
||||
| [iwantmyname](https://iwantmyname.com) | `iwantmyname` | `IWANTMYNAME_USERNAME` , `IWANTMYNAME_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/iwantmyname) |
|
||||
| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
|
||||
| [Liara](https://liara.ir) | `liara` | `LIARA_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/liara) |
|
||||
| [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 v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
|
||||
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
|
||||
| [Loopia](https://loopia.com/) | `loopia` | `LOOPIA_API_PASSWORD`, `LOOPIA_API_USER` | [Additional configuration](https://go-acme.github.io/lego/dns/loopia) |
|
||||
| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) |
|
||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
|
||||
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
|
||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
|
||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
|
||||
| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) |
|
||||
| [NearlyFreeSpeech.NET](https://www.nearlyfreespeech.net/) | `nearlyfreespeech` | `NEARLYFREESPEECH_API_KEY`, `NEARLYFREESPEECH_LOGIN` | [Additional configuration](https://go-acme.github.io/lego/dns/nearlyfreespeech) |
|
||||
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) |
|
||||
| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) |
|
||||
| [Nicmanager](https://www.nicmanager.com) | `nicmanager` | `NICMANAGER_API_EMAIL`, `NICMANAGER_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/nicmanager) |
|
||||
| [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) |
|
||||
| [Njalla](https://njal.la) | `njalla` | `NJALLA_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/njalla) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [Porkbun](https://porkbun.com/) | `porkbun` | `PORKBUN_SECRET_API_KEY`, `PORKBUN_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/porkbun) |
|
||||
| [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) |
|
||||
| [reg.ru](https://www.reg.ru) | `regru` | `REGRU_USERNAME`, `REGRU_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/regru) |
|
||||
| [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) |
|
||||
| [RimuHosting](https://rimuhosting.com) | `rimuhosting` | `RIMUHOSTING_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rimuhosting) |
|
||||
| [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) |
|
||||
| [Scaleway](https://www.scaleway.com) | `scaleway` | `SCALEWAY_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/scaleway) |
|
||||
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) |
|
||||
| [Servercow](https://servercow.de) | `servercow` | `SERVERCOW_USERNAME`, `SERVERCOW_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/servercow) |
|
||||
| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) |
|
||||
| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) |
|
||||
| [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) |
|
||||
| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) |
|
||||
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) |
|
||||
| [UKFast SafeDNS](https://docs.ukfast.co.uk/domains/safedns/index.html) | `safedns` | `SAFEDNS_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/safedns) |
|
||||
| [Ultradns](https://neustarsecurityservices.com/dns-services) | `ultradns` | `ULTRADNS_USERNAME`, `ULTRADNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/ultradns) |
|
||||
| [Variomedia](https://www.variomedia.de/) | `variomedia` | `VARIOMEDIA_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/variomedia) |
|
||||
| [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) |
|
||||
| [Vercel](https://vercel.com) | `vercel` | `VERCEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vercel) |
|
||||
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
|
||||
| [VinylDNS](https://www.vinyldns.io) | `vinyldns` | `VINYLDNS_ACCESS_KEY`, `VINYLDNS_SECRET_KEY`, `VINYLDNS_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/vinyldns) |
|
||||
| [VK Cloud](https://mcs.mail.ru/) | `vkcloud` | `VK_CLOUD_PASSWORD`, `VK_CLOUD_PROJECT_ID`, `VK_CLOUD_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/vkcloud) |
|
||||
| [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) |
|
||||
| [Websupport](https://websupport.sk) | `websupport` | `WEBSUPPORT_API_KEY`, `WEBSUPPORT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/websupport) |
|
||||
| [WEDOS](https://www.wedos.com) | `wedos` | `WEDOS_USERNAME`, `WEDOS_WAPI_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/wedos) |
|
||||
| [Yandex Cloud](https://cloud.yandex.com/en/) | `yandexcloud` | `YANDEX_CLOUD_FOLDER_ID`, `YANDEX_CLOUD_IAM_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandexcloud) |
|
||||
| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) |
|
||||
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) |
|
||||
| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) |
|
||||
| External Program | `exec` | `EXEC_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/exec) |
|
||||
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
|
||||
| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
|
||||
| Provider Name | Provider Code | Environment Variables | |
|
||||
|------------------------------------------------------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
|
||||
| [ACME DNS](https://github.com/joohoi/acme-dns) | `acme-dns` | `ACME_DNS_API_BASE`, `ACME_DNS_STORAGE_PATH`, `ACME_DNS_STORAGE_BASE_URL` | [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) |
|
||||
| [all-inkl](https://all-inkl.com) | `allinkl` | `ALL_INKL_LOGIN`, `ALL_INKL_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/allinkl) |
|
||||
| [ArvanCloud](https://www.arvancloud.ir/en) | `arvancloud` | `ARVANCLOUD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/arvancloud) |
|
||||
| [Auroradns](https://www.pcextreme.com/dns-health-checks) | `auroradns` | `AURORA_USER_ID`, `AURORA_KEY`, `AURORA_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/auroradns) |
|
||||
| [Autodns](https://www.internetx.com/domains/autodns/) | `autodns` | `AUTODNS_API_USER`, `AUTODNS_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/autodns) |
|
||||
| [Azure](https://azure.microsoft.com/services/dns/) (DEPRECATED) | `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) |
|
||||
| [AzureDNS](https://azure.microsoft.com/services/dns/) | `azuredns` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_ENVIRONMENT]`, `[AZURE_PRIVATE_ZONE]`, `[AZURE_ZONE_NAME]` | [Additional configuration](https://go-acme.github.io/lego/dns/azuredns) |
|
||||
| [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) |
|
||||
| [Brandit](https://www.brandit.com) (DEPRECATED) | `brandit` | `BRANDIT_API_USERNAME`, `BRANDIT_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/brandit) |
|
||||
| [Bunny](https://bunny.net) | `bunny` | `BUNNY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/bunny) |
|
||||
| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) |
|
||||
| [Civo](https://www.civo.com/) | `civo` | `CIVO_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/civo) |
|
||||
| [Cloud.ru](https://cloud.ru) | `cloudru` | `CLOUDRU_SERVICE_INSTANCE_ID`, `CLOUDRU_KEY_ID`, `CLOUDRU_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudru) |
|
||||
| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) |
|
||||
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
|
||||
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
|
||||
| [CloudXNS](https://www.cloudxns.net) (DEPRECATED) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
|
||||
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
|
||||
| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) |
|
||||
| [Core-Networks](https://www.core-networks.de) | `corenetworks` | `CORENETWORKS_LOGIN`, `CORENETWORKS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/corenetworks) |
|
||||
| [CPanel and WHM](https://cpanel.net/) | `cpanel` | `CPANEL_MODE`, `CPANEL_USERNAME`, `CPANEL_TOKEN`, `CPANEL_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/cpanel) |
|
||||
| [Derak Cloud](https://derak.cloud/) | `derak` | `DERAK_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/derak) |
|
||||
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
|
||||
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
|
||||
| [DirectAdmin](https://www.directadmin.com) | `directadmin` | `DIRECTADMIN_API_URL` , `DIRECTADMIN_USERNAME`, `DIRECTADMIN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/directadmin) |
|
||||
| [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) |
|
||||
| [dnsHome.de](https://www.dnshome.de) | `dnsHomede` | `DNSHOMEDE_CREDENTIALS` | [Additional configuration](https://go-acme.github.io/lego/dns/dnshomede) |
|
||||
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
|
||||
| [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) |
|
||||
| [Domeneshop](https://domene.shop) | `domeneshop` | `DOMENESHOP_API_TOKEN`, `DOMENESHOP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/domeneshop) |
|
||||
| [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) |
|
||||
| [Dynu](https://www.dynu.com) | `dynu` | `DYNU_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dynu) |
|
||||
| [EasyDNS](https://easydns.com/) | `easydns` | `EASYDNS_TOKEN`, `EASYDNS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/easydns) |
|
||||
| [EdgeDNS](https://www.akamai.com/) | `edgedns` | `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`, `AKAMAI_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/edgedns) |
|
||||
| [Efficient IP](https://efficientip.com) | `efficientip` | `EFFICIENTIP_USERNAME`, `EFFICIENTIP_PASSWORD`, `EFFICIENTIP_HOSTNAME`, `EFFICIENTIP_DNS_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/efficientip) |
|
||||
| [Epik](https://www.epik.com) | `epik` | `EPIK_SIGNATURE` | [Additional configuration](https://go-acme.github.io/lego/dns/epik) |
|
||||
| [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/edgedns) |
|
||||
| [Freemyip.com](https://freemyip.com) | `freemyip` | `FREEMYIP_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/freemyip) |
|
||||
| [G-Core](https://gcore.com/dns/) | `gcore` | `GCORE_PERMANENT_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/gcore) |
|
||||
| [Gandi v5](https://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_PERSONAL_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/gandiv5) |
|
||||
| [Gandi](https://www.gandi.net) | `gandi` | `GANDI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/gandi) |
|
||||
| [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://www.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) |
|
||||
| [Google Domains](https://domains.google) | `googledomains` | `GOOGLE_DOMAINS_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/googledomains) |
|
||||
| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) |
|
||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
|
||||
| [Hosttech](https://www.hosttech.eu) | `hosttech` | `HOSTTECH_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hosttech) |
|
||||
| [http.net](https://www.http.net/) | `httpnet` | `HTTPNET_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/httpnet) |
|
||||
| [Huawei Cloud](https://huaweicloud.com) | `huaweicloud` | `HUAWEICLOUD_ACCESS_KEY_ID`, `HUAWEICLOUD_SECRET_ACCESS_KEY`, `HUAWEICLOUD_REGION` | [Additional configuration](https://go-acme.github.io/lego/dns/huaweicloud) |
|
||||
| [Hurricane Electric](https://dns.he.net) | `hurricane` | `HURRICANE_TOKENS` [^6] | [Additional configuration](https://go-acme.github.io/lego/dns/hurricane) |
|
||||
| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) |
|
||||
| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) |
|
||||
| [IIJ DNS Platform Service](https://www.iij.ad.jp) | `iijdpf` | `IIJ_DPF_API_TOKEN` , `IIJ_DPF_DPM_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iijdpf) |
|
||||
| [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) |
|
||||
| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USERNAME`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) |
|
||||
| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) |
|
||||
| [Internet.bs](https://internetbs.net) | `internetbs` | `INTERNET_BS_API_KEY`, `INTERNET_BS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/internetbs) |
|
||||
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
|
||||
| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) |
|
||||
| [IPv64](https://ipv64.net) | `ipv64` | `IPV64_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ipv64) |
|
||||
| [iwantmyname](https://iwantmyname.com) | `iwantmyname` | `IWANTMYNAME_USERNAME` , `IWANTMYNAME_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/iwantmyname) |
|
||||
| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
|
||||
| [Liara](https://liara.ir) | `liara` | `LIARA_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/liara) |
|
||||
| [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) |
|
||||
| [Lima-City](https://www.lima-city.de) | `limacity` | `LIMACITY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/limacity) |
|
||||
| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
|
||||
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
|
||||
| [Loopia](https://loopia.com/) | `loopia` | `LOOPIA_API_PASSWORD`, `LOOPIA_API_USER` | [Additional configuration](https://go-acme.github.io/lego/dns/loopia) |
|
||||
| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) |
|
||||
| [Mail-in-a-Box](https://mailinabox.email) | `mailinabox` | `MAILINABOX_EMAIL`, `MAILINABOX_PASSWORD`, `MAILINABOX_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/mailinabox) |
|
||||
| [ManageEngine CloudDNS](https://clouddns.manageengine.com) | `manageengine` | `MANAGEENGINE_CLIENT_ID`, `MANAGEENGINE_CLIENT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/manageengine) |
|
||||
| [Metaname](https://metaname.net) | `metaname` | `METANAME_ACCOUNT_REFERENCE`, `METANAME_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/metaname) |
|
||||
| [mijn.host](https://mijn.host/) | `mijnhost` | `MIJNHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/mijnhost) |
|
||||
| [Mittwald](https://www.mittwald.de) | `mittwald` | `MITTWALD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/mittwald) |
|
||||
| [myaddr.{tools,dev,io}](https://myaddr.tools/) | `myaddr` | `MYADDR_PRIVATE_KEYS_MAPPING` | [Additional configuration](https://go-acme.github.io/lego/dns/myaddr) |
|
||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
|
||||
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
|
||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
|
||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
|
||||
| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) |
|
||||
| [NearlyFreeSpeech.NET](https://www.nearlyfreespeech.net/) | `nearlyfreespeech` | `NEARLYFREESPEECH_API_KEY`, `NEARLYFREESPEECH_LOGIN` | [Additional configuration](https://go-acme.github.io/lego/dns/nearlyfreespeech) |
|
||||
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) |
|
||||
| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) |
|
||||
| [Nicmanager](https://www.nicmanager.com) | `nicmanager` | `NICMANAGER_API_EMAIL`, `NICMANAGER_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/nicmanager) |
|
||||
| [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) |
|
||||
| [Njalla](https://njal.la) | `njalla` | `NJALLA_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/njalla) |
|
||||
| [Nodion](https://www.nodion.com) | `nodion` | `NODION_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/nodion) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY`, `OVH_CLIENT_ID`, `OVH_CLIENT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/ovh) |
|
||||
| [Plesk](https://www.plesk.com) | `plesk` | `PLESK_SERVER_BASE_URL`, `PLESK_USERNAME`, `PLESK_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/plesk) |
|
||||
| [Porkbun](https://porkbun.com/) | `porkbun` | `PORKBUN_SECRET_API_KEY`, `PORKBUN_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/porkbun) |
|
||||
| [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) |
|
||||
| [Rainyun/雨云](https://www.rainyun.com) | `rainyun` | `RAINYUN_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rainyun) |
|
||||
| [RcodeZero](https://www.rcodezero.at) | `rcodezero` | `RCODEZERO_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/rcodezero) |
|
||||
| [reg.ru](https://www.reg.ru) | `regru` | `REGRU_USERNAME`, `REGRU_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/regru) |
|
||||
| [Regfish](https://regfish.de) | `regfish` | `regfish` | [Additional configuration](https://go-acme.github.io/lego/dns/regfish) |
|
||||
| [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) |
|
||||
| [RimuHosting](https://rimuhosting.com) | `rimuhosting` | `RIMUHOSTING_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rimuhosting) |
|
||||
| [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) |
|
||||
| [Scaleway](https://www.scaleway.com) | `scaleway` | `SCW_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/scaleway) |
|
||||
| [Selectel v2](https://selectel.ru/en/) | `selectelv2` | `SELECTELV2_ACCOUNT_ID`, `SELECTELV2_PASSWORD`, `SELECTELV2_PROJECT_ID`, `SELECTELV2_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/selectelv2) |
|
||||
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/selectel) |
|
||||
| [SelfHost.(de/eu)](https://www.selfhost.de) | `selfhostde` | `SELFHOSTDE_USERNAME`, `SELFHOSTDE_PASSWORD`, `SELFHOSTDE_RECORDS_MAPPING` | [Additional configuration](https://go-acme.github.io/lego/dns/selfhostde) |
|
||||
| [Servercow](https://servercow.de) | `servercow` | `SERVERCOW_USERNAME`, `SERVERCOW_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/servercow) |
|
||||
| [Shellrent](https://www.shellrent.com) | `shellrent` | `SHELLRENT_USERNAME`, `SHELLRENT_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/shellrent) |
|
||||
| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) |
|
||||
| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) |
|
||||
| [Spaceship](https://spaceship.com) | `spaceship` | `SPACESHIP_API_KEY`, `SPACESHIP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/spaceship) |
|
||||
| [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) |
|
||||
| [Technitium](https://technitium.com) | `technitium` | `TECHNITIUM_SERVER_BASE_URL`, `TECHNITIUM_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/technitium) |
|
||||
| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) |
|
||||
| [Timeweb Cloud](https://timeweb.cloud) | `timewebcloud` | `TIMEWEBCLOUD_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/timewebcloud) |
|
||||
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) |
|
||||
| [UKFast SafeDNS](https://docs.ukfast.co.uk/domains/safedns/index.html) | `safedns` | `SAFEDNS_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/safedns) |
|
||||
| [Ultradns](https://neustarsecurityservices.com/dns-services) | `ultradns` | `ULTRADNS_USERNAME`, `ULTRADNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/ultradns) |
|
||||
| [Variomedia](https://www.variomedia.de/) | `variomedia` | `VARIOMEDIA_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/variomedia) |
|
||||
| [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) |
|
||||
| [Vercel](https://vercel.com) | `vercel` | `VERCEL_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vercel) |
|
||||
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
|
||||
| [VinylDNS](https://www.vinyldns.io) | `vinyldns` | `VINYLDNS_ACCESS_KEY`, `VINYLDNS_SECRET_KEY`, `VINYLDNS_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/vinyldns) |
|
||||
| [VK Cloud](https://mcs.mail.ru/) | `vkcloud` | `VK_CLOUD_PASSWORD`, `VK_CLOUD_PROJECT_ID`, `VK_CLOUD_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/vkcloud) |
|
||||
| [Volcano Engine](https://www.volcengine.com) | `volcengine` | `VOLC_ACCESSKEY`, `VOLC_SECRETKEY` | [Additional configuration](https://go-acme.github.io/lego/dns/volcengine) |
|
||||
| [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) |
|
||||
| [Webnames](https://www.webnames.ru/) | `webnames` | `WEBNAMES_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/webnames) |
|
||||
| [Websupport](https://websupport.sk) | `websupport` | `WEBSUPPORT_API_KEY`, `WEBSUPPORT_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/websupport) |
|
||||
| [WEDOS](https://www.wedos.com) | `wedos` | `WEDOS_USERNAME`, `WEDOS_WAPI_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/wedos) |
|
||||
| [West.cn/西部数码](https://www.west.cn) | `westcn` | `WESTCN_USERNAME`, `WESTCN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/westcn) |
|
||||
| [Yandex 360](https://360.yandex.ru) | `yandex360` | `YANDEX360_OAUTH_TOKEN`, `YANDEX360_ORG_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex360) |
|
||||
| [Yandex Cloud](https://cloud.yandex.com/en/) | `yandexcloud` | `YANDEX_CLOUD_FOLDER_ID`, `YANDEX_CLOUD_IAM_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandexcloud) |
|
||||
| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) |
|
||||
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) |
|
||||
| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) |
|
||||
| External Program | `exec` | `EXEC_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/exec) |
|
||||
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
|
||||
| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
|
||||
|
||||
[^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).
|
||||
@ -431,11 +472,6 @@ For complete details, refer to your provider's _Additional configuration_ link.
|
||||
[^5]: The `Global API Key` needs to be used, not the `Origin CA Key`.
|
||||
[^6]: As explained in the [LEGO hurricane configuration](https://go-acme.github.io/lego/dns/hurricane/#credentials), each domain or wildcard (record name) needs a token. So each update of record name must be followed by an update of the `HURRICANE_TOKENS` variable, and a restart of Traefik.
|
||||
|
||||
!!! info "`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.
|
||||
@ -465,6 +501,150 @@ certificatesResolvers:
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||
```
|
||||
|
||||
#### `propagation.delayBeforeChecks`
|
||||
|
||||
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
||||
|
||||
You can delay this operation by specifying a delay (in seconds) with `delayBeforeChecks` (value must be greater than zero).
|
||||
|
||||
This option is useful when internal networks block external DNS queries.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
# ...
|
||||
propagation:
|
||||
# ...
|
||||
delayBeforeChecks: 2s
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
|
||||
# ...
|
||||
delayBeforeChecks = "2s"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.delayBeforeChecks=2s
|
||||
```
|
||||
|
||||
#### `propagation.disableChecks`
|
||||
|
||||
Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready.
|
||||
|
||||
Please note that disabling checks can prevent the challenge from succeeding.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
# ...
|
||||
propagation:
|
||||
# ...
|
||||
disableChecks: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
|
||||
# ...
|
||||
disableChecks = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.disableChecks=true
|
||||
```
|
||||
|
||||
#### `propagation.requireAllRNS`
|
||||
|
||||
Requires the challenge TXT record to be propagated to all recursive nameservers.
|
||||
|
||||
!!! note
|
||||
|
||||
If you have disabled authoritative nameservers checks (with `propagation.disableANSChecks`),
|
||||
it is recommended to check all recursive nameservers instead.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
# ...
|
||||
propagation:
|
||||
# ...
|
||||
requireAllRNS: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
|
||||
# ...
|
||||
requireAllRNS = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.requireAllRNS=true
|
||||
```
|
||||
|
||||
#### `propagation.disableANSChecks`
|
||||
|
||||
Disables the challenge TXT record propagation checks against authoritative nameservers.
|
||||
|
||||
This option will skip the propagation check against the nameservers of the authority (SOA).
|
||||
|
||||
It should be used only if the nameservers of the authority are not reachable.
|
||||
|
||||
!!! note
|
||||
|
||||
If you have disabled authoritative nameservers checks,
|
||||
it is recommended to check all recursive nameservers instead.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
dnsChallenge:
|
||||
# ...
|
||||
propagation:
|
||||
# ...
|
||||
disableANSChecks: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge]
|
||||
# ...
|
||||
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
|
||||
# ...
|
||||
disableANSChecks = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.disableANSChecks=true
|
||||
```
|
||||
|
||||
#### Wildcard Domains
|
||||
|
||||
[ACME V2](https://community.letsencrypt.org/t/acme-v2-and-wildcard-certificate-support-is-live/55579) supports wildcard certificates.
|
||||
@ -581,9 +761,22 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||
|
||||
_Optional, Default=2160_
|
||||
|
||||
The `certificatesDuration` option defines the certificates' duration in hours.
|
||||
`certificatesDuration` is used to calculate two durations:
|
||||
|
||||
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.
|
||||
- `Renew Interval`: the interval between renew attempts.
|
||||
|
||||
It defaults to `2160` (90 days) to follow Let's Encrypt certificates' duration.
|
||||
|
||||
| Certificate Duration | Renew Period | Renew Interval |
|
||||
|----------------------|-------------------|-------------------------|
|
||||
| >= 1 year | 4 months | 1 week |
|
||||
| >= 90 days | 30 days | 1 day |
|
||||
| >= 30 days | 10 days | 12 hours |
|
||||
| >= 7 days | 1 day | 1 hour |
|
||||
| >= 24 hours | 6 hours | 10 min |
|
||||
| < 24 hours | 20 min | 1 min |
|
||||
|
||||
!!! warning "Traefik cannot manage certificates with a duration lower than 1 hour."
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
@ -608,19 +801,6 @@ certificatesResolvers:
|
||||
# ...
|
||||
```
|
||||
|
||||
`certificatesDuration` is used to calculate two durations:
|
||||
|
||||
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.
|
||||
- `Renew Interval`: the interval between renew attempts.
|
||||
|
||||
| Certificate Duration | Renew Period | Renew Interval |
|
||||
|----------------------|-------------------|-------------------------|
|
||||
| >= 1 year | 4 months | 1 week |
|
||||
| >= 90 days | 30 days | 1 day |
|
||||
| >= 7 days | 1 day | 1 hour |
|
||||
| >= 24 hours | 6 hours | 10 min |
|
||||
| < 24 hours | 20 min | 1 min |
|
||||
|
||||
### `preferredChain`
|
||||
|
||||
_Optional, Default=""_
|
||||
@ -680,6 +860,109 @@ certificatesResolvers:
|
||||
# ...
|
||||
```
|
||||
|
||||
### `caCertificates`
|
||||
|
||||
_Optional, Default=[]_
|
||||
|
||||
The `caCertificates` option specifies the paths to PEM encoded CA Certificates that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
caCertificates:
|
||||
- path/certificates1.pem
|
||||
- path/certificates2.pem
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
caCertificates = [ "path/certificates1.pem", "path/certificates2.pem" ]
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.caCertificates="path/certificates1.pem,path/certificates2.pem"
|
||||
# ...
|
||||
```
|
||||
|
||||
??? note "LEGO Environment Variable"
|
||||
|
||||
It can be defined globally by using the environment variable `LEGO_CA_CERTIFICATES`.
|
||||
This environment variable is neither a fallback nor an override of the configuration option.
|
||||
|
||||
### `caSystemCertPool`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
The `caSystemCertPool` option defines if the certificates pool must use a copy of the system cert pool.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
caSystemCertPool: true
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
caSystemCertPool = true
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.caSystemCertPool=true
|
||||
# ...
|
||||
```
|
||||
|
||||
??? note "LEGO Environment Variable"
|
||||
|
||||
It can be defined globally by using the environment variable `LEGO_CA_SYSTEM_CERT_POOL`.
|
||||
`LEGO_CA_SYSTEM_CERT_POOL` is ignored if `LEGO_CA_CERTIFICATES` is not set or empty.
|
||||
This environment variable is neither a fallback nor an override of the configuration option.
|
||||
|
||||
### `caServerName`
|
||||
|
||||
_Optional, Default=""_
|
||||
|
||||
The `caServerName` option specifies the CA server name that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
acme:
|
||||
# ...
|
||||
caServerName: "my-server"
|
||||
# ...
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.acme]
|
||||
# ...
|
||||
caServerName = "my-server"
|
||||
# ...
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.acme.caServerName="my-server"
|
||||
# ...
|
||||
```
|
||||
|
||||
??? note "LEGO Environment Variable"
|
||||
|
||||
It can be defined globally by using the environment variable `LEGO_CA_SERVER_NAME`.
|
||||
`LEGO_CA_SERVER_NAME` is ignored if `LEGO_CA_CERTIFICATES` is not set or empty.
|
||||
This environment variable is neither a fallback nor an override of the configuration option.
|
||||
|
||||
## Fallback
|
||||
|
||||
If Let's Encrypt is not reachable, the following certificates will apply:
|
||||
|
@ -1,26 +1,14 @@
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
|
||||
- traefik.http.routers.blog.tls=true
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
- traefik.http.routers.blog.tls.domains[0].main=example.org
|
||||
- traefik.http.routers.blog.tls.domains[0].main=example.com
|
||||
- traefik.http.routers.blog.tls.domains[0].sans=*.example.org
|
||||
```
|
||||
|
||||
```yaml tab="Docker (Swarm)"
|
||||
## Dynamic configuration
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
|
||||
- traefik.http.services.blog-svc.loadbalancer.server.port=8080"
|
||||
- traefik.http.routers.blog.tls=true
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
- traefik.http.routers.blog.tls.domains[0].main=example.org
|
||||
- traefik.http.routers.blog.tls.domains[0].sans=*.example.org
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
@ -38,32 +26,11 @@ spec:
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
domains:
|
||||
- main: example.org
|
||||
- main: example.com
|
||||
sans:
|
||||
- '*.example.org'
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
labels: {
|
||||
"traefik.http.routers.blog.rule": "Host(`example.com`) && Path(`/blog`)",
|
||||
"traefik.http.routers.blog.tls": "true",
|
||||
"traefik.http.routers.blog.tls.certresolver": "myresolver",
|
||||
"traefik.http.routers.blog.tls.domains[0].main": "example.com",
|
||||
"traefik.http.routers.blog.tls.domains[0].sans": "*.example.com",
|
||||
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
|
||||
- traefik.http.routers.blog.tls=true
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
- traefik.http.routers.blog.tls.domains[0].main=example.org
|
||||
- traefik.http.routers.blog.tls.domains[0].sans=*.example.org
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
@ -73,7 +40,7 @@ http:
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
domains:
|
||||
- main: "example.org"
|
||||
- main: "example.com"
|
||||
sans:
|
||||
- "*.example.org"
|
||||
```
|
||||
@ -86,6 +53,6 @@ http:
|
||||
[http.routers.blog.tls]
|
||||
certResolver = "myresolver" # From static configuration
|
||||
[[http.routers.blog.tls.domains]]
|
||||
main = "example.org"
|
||||
main = "example.com"
|
||||
sans = ["*.example.org"]
|
||||
```
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)
|
||||
@ -35,23 +35,6 @@ spec:
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
labels: {
|
||||
"traefik.http.routers.blog.rule": "(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)",
|
||||
"traefik.http.routers.blog.tls": "true",
|
||||
"traefik.http.routers.blog.tls.certresolver": "myresolver",
|
||||
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)
|
||||
- traefik.http.routers.blog.tls=true
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
|
||||
@ -35,23 +35,6 @@ spec:
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
labels: {
|
||||
"traefik.http.routers.blog.rule": "Host(`example.com`) && Path(`/blog`)",
|
||||
"traefik.http.routers.blog.tls": "true",
|
||||
"traefik.http.routers.blog.tls.certresolver": "myresolver",
|
||||
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
|
||||
- traefik.http.routers.blog.tls=true
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
|
56
docs/content/https/spiffe.md
Normal file
56
docs/content/https/spiffe.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "Traefik SPIFFE Documentation"
|
||||
description: "Learn how to configure Traefik to use SPIFFE. Read the technical documentation."
|
||||
---
|
||||
|
||||
# SPIFFE
|
||||
|
||||
Secure the backend connection with SPIFFE.
|
||||
{: .subtitle }
|
||||
|
||||
[SPIFFE](https://spiffe.io/docs/latest/spiffe-about/overview/) (Secure Production Identity Framework For Everyone),
|
||||
provides a secure identity in the form of a specially crafted X.509 certificate,
|
||||
to every workload in an environment.
|
||||
|
||||
Traefik is able to connect to the Workload API to obtain an x509-SVID used to secure the connection with SPIFFE enabled backends.
|
||||
|
||||
## Configuration
|
||||
|
||||
### General
|
||||
|
||||
Enabling SPIFFE is part of the [static configuration](../getting-started/configuration-overview.md#the-static-configuration).
|
||||
It can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
|
||||
### Workload API
|
||||
|
||||
The `workloadAPIAddr` configuration defines the address of the SPIFFE [Workload API](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-workload-api).
|
||||
|
||||
!!! info "Enabling SPIFFE in ServersTransports"
|
||||
|
||||
Enabling SPIFFE does not imply that backend connections are going to use it automatically.
|
||||
Each [ServersTransport](../routing/services/index.md#serverstransport_1) or [TCPServersTransport](../routing/services/index.md#serverstransport_2),
|
||||
that is meant to be secured with SPIFFE,
|
||||
must explicitly enable it (see [SPIFFE with ServersTransport](../routing/services/index.md#spiffe) or [SPIFFE with TCPServersTransport](../routing/services/index.md#spiffe_1)).
|
||||
|
||||
!!! warning "SPIFFE can cause Traefik to stall"
|
||||
When using SPIFFE,
|
||||
Traefik will wait for the first SVID to be delivered before starting.
|
||||
If Traefik is hanging when waiting on SPIFFE SVID delivery,
|
||||
please double check that it is correctly registered as workload in your SPIFFE infrastructure.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Static configuration
|
||||
spiffe:
|
||||
workloadAPIAddr: localhost
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Static configuration
|
||||
[spiffe]
|
||||
workloadAPIAddr: localhost
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--spiffe.workloadAPIAddr=localhost
|
||||
```
|
207
docs/content/https/tailscale.md
Normal file
207
docs/content/https/tailscale.md
Normal file
@ -0,0 +1,207 @@
|
||||
---
|
||||
title: "Traefik Tailscale Documentation"
|
||||
description: "Learn how to configure Traefik Proxy to resolve TLS certificates for your Tailscale services. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Tailscale
|
||||
|
||||
Provision TLS certificates for your internal Tailscale services.
|
||||
{: .subtitle }
|
||||
|
||||
To protect a service with TLS, a certificate from a public Certificate Authority is needed.
|
||||
In addition to its vpn role, Tailscale can also [provide certificates](https://tailscale.com/kb/1153/enabling-https/) for the machines in your Tailscale network.
|
||||
|
||||
## Certificate resolvers
|
||||
|
||||
To obtain a TLS certificate from the Tailscale daemon,
|
||||
a Tailscale certificate resolver needs to be configured as below.
|
||||
|
||||
!!! info "Referencing a certificate resolver"
|
||||
|
||||
Defining a certificate resolver does not imply that routers are going to use it automatically.
|
||||
Each router or entrypoint that is meant to use the resolver must explicitly [reference](../routing/routers/index.md#certresolver) it.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
tailscale: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[certificatesResolvers.myresolver.tailscale]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--certificatesresolvers.myresolver.tailscale=true
|
||||
```
|
||||
|
||||
## Domain Definition
|
||||
|
||||
A certificate resolver requests certificates for a set of domain names inferred from routers, according to the following:
|
||||
|
||||
- If the router has a [`tls.domains`](../routing/routers/index.md#domains) option set,
|
||||
then the certificate resolver derives this router domain name from the `main` option of `tls.domains`.
|
||||
|
||||
- Otherwise, the certificate resolver derives the domain name from any `Host()` or `HostSNI()` matchers
|
||||
in the [router's rule](../routing/routers/index.md#rule).
|
||||
|
||||
!!! info "Tailscale Domain Format"
|
||||
|
||||
The domain is only taken into account if it is a Tailscale-specific one,
|
||||
i.e. of the form `machine-name.domains-alias.ts.net`.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
!!! example "Enabling Tailscale certificate resolution"
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
certificatesResolvers:
|
||||
myresolver:
|
||||
tailscale: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.websecure]
|
||||
address = ":443"
|
||||
|
||||
[certificatesResolvers.myresolver.tailscale]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesresolvers.myresolver.tailscale=true
|
||||
```
|
||||
|
||||
!!! example "Domain from Router's Rule Example"
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
```yaml tab="Docker (Swarm)"
|
||||
## Dynamic configuration
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: blogtls
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: blog
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
routers:
|
||||
blog:
|
||||
rule: "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.blog]
|
||||
rule = "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
|
||||
[http.routers.blog.tls]
|
||||
certResolver = "myresolver"
|
||||
```
|
||||
|
||||
!!! example "Domain from Router's tls.domain Example"
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Path(`/metrics`)
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
- traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
|
||||
```
|
||||
|
||||
```yaml tab="Docker (Swarm)"
|
||||
## Dynamic configuration
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.http.routers.blog.rule=Path(`/metrics`)
|
||||
- traefik.http.routers.blog.tls.certresolver=myresolver
|
||||
- traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: blogtls
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Path(`/metrics`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: blog
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
domains:
|
||||
- main: monitoring.yak-bebop.ts.net
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
routers:
|
||||
blog:
|
||||
rule: "Path(`/metrics`)"
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
domains:
|
||||
- main: "monitoring.yak-bebop.ts.net"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
## Dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.blog]
|
||||
rule = "Path(`/metrics`)"
|
||||
[http.routers.blog.tls]
|
||||
certResolver = "myresolver"
|
||||
[[http.routers.blog.tls.domains]]
|
||||
main = "monitoring.yak-bebop.ts.net"
|
||||
```
|
||||
|
||||
## Automatic Renewals
|
||||
|
||||
Traefik automatically tracks the expiry date of each Tailscale certificate it fetches,
|
||||
and starts to renew a certificate 14 days before its expiry to match Tailscale daemon renew policy.
|
@ -211,7 +211,7 @@ spec:
|
||||
- bar.example.org
|
||||
```
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
## Dynamic configuration
|
||||
labels:
|
||||
- "traefik.tls.stores.default.defaultgeneratedcert.resolver=myresolver"
|
||||
@ -219,14 +219,6 @@ labels:
|
||||
- "traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
labels: {
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.resolver": "myresolver",
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.domain.main": "example.org",
|
||||
"traefik.tls.stores.default.defaultgeneratedcert.domain.sans": "foo.example.org, bar.example.org",
|
||||
}
|
||||
```
|
||||
|
||||
## TLS Options
|
||||
|
||||
The TLS options allow one to configure some parameters of the TLS connection.
|
||||
@ -509,15 +501,17 @@ spec:
|
||||
|
||||
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`.
|
||||
For authentication policies that require verification of the client certificate, the certificate authority for the certificates should be set in `clientAuth.caFiles`.
|
||||
|
||||
In Kubernetes environment, CA certificate can be set in `clientAuth.secretNames`. See [TLSOption resource](../../routing/providers/kubernetes-crd#kind-tlsoption) for more details.
|
||||
|
||||
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`.
|
||||
- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`.
|
||||
- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`. Otherwise proceeds without any certificate.
|
||||
- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `clientAuth.caFiles` or in `clientAuth.secretNames`.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Dynamic configuration
|
||||
|
3
docs/content/includes/kubernetes-requirements.md
Normal file
3
docs/content/includes/kubernetes-requirements.md
Normal file
@ -0,0 +1,3 @@
|
||||
Traefik follows the [Kubernetes support policy](https://kubernetes.io/releases/version-skew-policy/#supported-versions),
|
||||
and supports at least the latest three minor versions of Kubernetes.
|
||||
General functionality cannot be guaranteed for older versions.
|
@ -1,11 +1,10 @@
|
||||
---
|
||||
|
||||
!!! question "Using Traefik for Business Applications?"
|
||||
!!! question "Using Traefik OSS in Production?"
|
||||
|
||||
If you are using Traefik in your organization, consider [Traefik Enterprise](https://traefik.io/traefik-enterprise/). You can use it as your:
|
||||
If you are using Traefik at work, consider adding enterprise-grade API gateway capabilities or commercial support for Traefik OSS.
|
||||
|
||||
- [API Gateway](https://traefik.io/solutions/api-gateway/)
|
||||
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
|
||||
- [Docker Swarm Ingress Controller](https://traefik.io/solutions/docker-swarm-ingress/)
|
||||
- [Watch our API Gateway Demo Video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc)
|
||||
- [Request 24/7/365 OSS Support](https://info.traefik.io/request-commercial-support?cta=doc)
|
||||
|
||||
Traefik Enterprise simplifies the discovery, security, and deployment of APIs and microservices across any environment. See it in action in [this short video walkthrough](https://info.traefik.io/watch-traefikee-demo).
|
||||
Adding API Gateway capabilities to Traefik OSS is fast and seamless. There's no rip and replace and all configurations remain intact. See it in action via [this short video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc).
|
||||
|
@ -7,25 +7,27 @@ description: "Traefik Proxy, an open source Edge Router, auto-discovers configur
|
||||
|
||||

|
||||
|
||||
Traefik is an [open-source](https://github.com/traefik/traefik) *Edge Router* that makes publishing your services a fun and easy experience.
|
||||
It receives requests on behalf of your system and finds out which components are responsible for handling them.
|
||||
Traefik is an [open-source](https://github.com/traefik/traefik) *Application Proxy* that makes publishing your services a fun and easy experience.
|
||||
It receives requests on behalf of your system and identifies which components are responsible for handling them, and routes them securely.
|
||||
|
||||
What sets Traefik apart, besides its many features, is that it automatically discovers the right configuration for your services.
|
||||
The magic happens when Traefik inspects your infrastructure, where it finds relevant information and discovers which service serves which request.
|
||||
|
||||
Traefik is natively compliant with every major cluster technology, such as Kubernetes, Docker, Docker Swarm, AWS, Mesos, Marathon, and [the list goes on](providers/overview.md); and can handle many at the same time. (It even works for legacy software running on bare metal.)
|
||||
Traefik is natively compliant with every major cluster technology, such as Kubernetes, Docker Swarm, AWS, and [the list goes on](providers/overview.md); and can handle many at the same time. (It even works for legacy software running on bare metal.)
|
||||
|
||||
With Traefik, there is no need to maintain and synchronize a separate configuration file: everything happens automatically, in real time (no restarts, no connection interruptions).
|
||||
With Traefik, you spend time developing and deploying new features to your system, not on configuring and maintaining its working state.
|
||||
With Traefik, you spend time developing and deploying new features to your system, not on configuring and maintaining its working state.
|
||||
|
||||
Developing Traefik, our main goal is to make it simple to use, and we're sure you'll enjoy it.
|
||||
And if your needs change, you can add API gateway and API management capabilities seamlessly to your existing Traefik deployments. It takes less than a minute, there’s no rip-and-replace, and all your configurations are preserved. See this in action in [our API gateway demo video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=docs).
|
||||
|
||||
Developing Traefik, our main goal is to make it effortless to use, and we're sure you'll enjoy it.
|
||||
|
||||
-- The Traefik Maintainer Team
|
||||
|
||||
!!! info
|
||||
|
||||
Join our user friendly and active [Community Forum]((https://community.traefik.io "Link to Traefik Community Forum") to discuss, learn, and connect with the traefik community.
|
||||
Have a question? Join our [Community Forum](https://community.traefik.io "Link to Traefik Community Forum") to discuss, learn, and connect with the Traefik community.
|
||||
|
||||
Using Traefik in your organization? Consider [Traefik Enterprise](https://traefik.io/traefik-enterprise/ "Lino to Traefik Enterprise"), our unified API Gateway and Ingress that simplifies the discovery, security, and deployment of APIs and microservices across any environment.
|
||||
Using Traefik OSS in Production? Consider our enterprise-grade [API Gateway](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc) or our [24/7/365 OSS Support](https://info.traefik.io/request-commercial-support?cta=doc).
|
||||
|
||||
See it in action in [this short video walkthrough](https://info.traefik.io/watch-traefikee-demo "Link to video walkthrough").
|
||||
Explore our API Gateway upgrade via [this short demo video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc).
|
||||
|
@ -14,7 +14,7 @@ The AddPrefix middleware updates the path of a request before forwarding it.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Prefixing with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
|
||||
@ -36,18 +36,6 @@ spec:
|
||||
- "traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.add-foo.addprefix.prefix": "/foo"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Prefixing with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Prefixing with /foo
|
||||
http:
|
||||
|
@ -10,18 +10,18 @@ Adding Basic Authentication
|
||||
|
||||

|
||||
|
||||
The BasicAuth middleware restricts access to your services to known users.
|
||||
The BasicAuth middleware grants access to services to authorized users only.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Declaring the user list
|
||||
#
|
||||
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
|
||||
# To create user:password pair, it's possible to use this command:
|
||||
# echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
|
||||
#
|
||||
# Also note that dollar signs should NOT be doubled when they not evaluated (e.g. Ansible docker_container module).
|
||||
# Also note that dollar signs should NOT be doubled when they are not being evaluated (e.g. Ansible docker_container module).
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
@ -41,18 +41,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Declaring the user list
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Declaring the user list
|
||||
http:
|
||||
@ -100,7 +88,7 @@ The `users` option is an array of authorized users. Each user must be declared u
|
||||
Please note that these keys are not hashed or encrypted in any way, and therefore is less secure than other methods.
|
||||
You can find more information on the [Kubernetes Basic Authentication Secret Documentation](https://kubernetes.io/docs/concepts/configuration/secret/#basic-authentication-secret)
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Declaring the user list
|
||||
#
|
||||
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
|
||||
@ -157,18 +145,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Declaring the user list
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Declaring the user list
|
||||
http:
|
||||
@ -201,7 +177,7 @@ The file content is a list of `name:hashed-password`.
|
||||
- If both `users` and `usersFile` are provided, the two are merged. The contents of `usersFile` have precedence over the values in `users`.
|
||||
- Because it does not make much sense to refer to a file path on Kubernetes, the `usersFile` field doesn't exist for Kubernetes IngressRoute, and one should use the `secret` field instead.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
@ -232,17 +208,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.basicauth.usersfile": "/path/to/my/usersfile"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -268,7 +233,7 @@ http:
|
||||
|
||||
You can customize the realm for the authentication with the `realm` option. The default value is `traefik`.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.realm=MyRealm"
|
||||
```
|
||||
@ -287,17 +252,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.realm=MyRealm"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.basicauth.realm": "MyRealm"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.realm=MyRealm"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -316,7 +270,7 @@ http:
|
||||
|
||||
You can define a header field to store the authenticated user using the `headerField`option.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.my-auth.basicauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
@ -336,12 +290,6 @@ spec:
|
||||
- "traefik.http.middlewares.my-auth.basicauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.my-auth.basicauth.headerField": "X-WebAuth-User"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -361,7 +309,7 @@ http:
|
||||
|
||||
Set the `removeHeader` option to `true` to remove the authorization header before forwarding the request to your service. (Default value is `false`.)
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.removeheader=true"
|
||||
```
|
||||
@ -380,17 +328,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.removeheader=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.basicauth.removeheader": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.basicauth.removeheader=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -404,3 +341,5 @@ http:
|
||||
[http.middlewares.test-auth.basicAuth]
|
||||
removeHeader = true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -18,7 +18,7 @@ This can help services avoid large amounts of data (`multipart/form-data` for ex
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Sets the maximum request body to 2MB
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
@ -40,18 +40,6 @@ spec:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.maxRequestBodyBytes": "2000000"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Sets the maximum request body to 2MB
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Sets the maximum request body to 2MB
|
||||
http:
|
||||
@ -78,7 +66,7 @@ The `maxRequestBodyBytes` option configures the maximum allowed body size for th
|
||||
|
||||
If the request exceeds the allowed size, it is not forwarded to the service, and the client gets a `413` (Request Entity Too Large) response.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
@ -97,17 +85,6 @@ spec:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.maxRequestBodyBytes": "2000000"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -128,7 +105,7 @@ _Optional, Default=1048576_
|
||||
|
||||
You can configure a threshold (in bytes) from which the request will be buffered on disk instead of in memory with the `memRequestBodyBytes` option.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=2000000"
|
||||
```
|
||||
@ -147,17 +124,6 @@ spec:
|
||||
- "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.memRequestBodyBytes": "2000000"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -180,7 +146,7 @@ The `maxResponseBodyBytes` option configures the maximum allowed response size f
|
||||
|
||||
If the response exceeds the allowed size, it is not forwarded to the client. The client gets a `500` (Internal Server Error) response instead.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=2000000"
|
||||
```
|
||||
@ -199,17 +165,6 @@ spec:
|
||||
- "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.maxResponseBodyBytes": "2000000"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -230,7 +185,7 @@ _Optional, Default=1048576_
|
||||
|
||||
You can configure a threshold (in bytes) from which the response will be buffered on disk instead of in memory with the `memResponseBodyBytes` option.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=2000000"
|
||||
```
|
||||
@ -249,17 +204,6 @@ spec:
|
||||
- "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.memResponseBodyBytes": "2000000"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=2000000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -282,7 +226,7 @@ You can have the Buffering middleware replay the request using `retryExpression`
|
||||
|
||||
??? example "Retries once in the case of a network error"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.retryExpression=IsNetworkError() && Attempts() < 2"
|
||||
```
|
||||
@ -301,17 +245,6 @@ You can have the Buffering middleware replay the request using `retryExpression`
|
||||
- "traefik.http.middlewares.limit.buffering.retryExpression=IsNetworkError() && Attempts() < 2"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.limit.buffering.retryExpression": "IsNetworkError() && Attempts() < 2"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.limit.buffering.retryExpression=IsNetworkError() && Attempts() < 2"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
|
@ -15,9 +15,9 @@ It makes reusing the same groups easier.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Below is an example of a Chain containing `WhiteList`, `BasicAuth`, and `RedirectScheme`.
|
||||
Below is an example of a Chain containing `AllowList`, `BasicAuth`, and `RedirectScheme`.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.routers.router1.service=service1"
|
||||
- "traefik.http.routers.router1.middlewares=secured"
|
||||
@ -25,7 +25,7 @@ labels:
|
||||
- "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users"
|
||||
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
@ -80,7 +80,7 @@ kind: Middleware
|
||||
metadata:
|
||||
name: known-ips
|
||||
spec:
|
||||
ipWhiteList:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 192.168.1.7
|
||||
- 127.0.0.1/32
|
||||
@ -93,35 +93,10 @@ spec:
|
||||
- "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users"
|
||||
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.routers.router1.service": "service1",
|
||||
"traefik.http.routers.router1.middlewares": "secured",
|
||||
"traefik.http.routers.router1.rule": "Host(`mydomain`)",
|
||||
"traefik.http.middlewares.secured.chain.middlewares": "https-only,known-ips,auth-users",
|
||||
"traefik.http.middlewares.auth-users.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"traefik.http.middlewares.https-only.redirectscheme.scheme": "https",
|
||||
"traefik.http.middlewares.known-ips.ipwhitelist.sourceRange": "192.168.1.7,127.0.0.1/32",
|
||||
"traefik.http.services.service1.loadbalancer.server.port": "80"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.routers.router1.service=service1"
|
||||
- "traefik.http.routers.router1.middlewares=secured"
|
||||
- "traefik.http.routers.router1.rule=Host(`mydomain`)"
|
||||
- "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users"
|
||||
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
|
||||
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# ...
|
||||
http:
|
||||
@ -150,7 +125,7 @@ http:
|
||||
scheme: https
|
||||
|
||||
known-ips:
|
||||
ipWhiteList:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "192.168.1.7"
|
||||
- "127.0.0.1/32"
|
||||
@ -180,7 +155,7 @@ http:
|
||||
[http.middlewares.https-only.redirectScheme]
|
||||
scheme = "https"
|
||||
|
||||
[http.middlewares.known-ips.ipWhiteList]
|
||||
[http.middlewares.known-ips.ipAllowList]
|
||||
sourceRange = ["192.168.1.7", "127.0.0.1/32"]
|
||||
|
||||
[http.services]
|
||||
|
@ -30,7 +30,7 @@ To assess if your system is healthy, the circuit breaker constantly monitors the
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Latency Check
|
||||
labels:
|
||||
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||
@ -52,18 +52,6 @@ spec:
|
||||
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.latency-check.circuitbreaker.expression": "LatencyAtQuantileMS(50.0) > 100"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Latency Check
|
||||
labels:
|
||||
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Latency Check
|
||||
http:
|
||||
@ -97,6 +85,7 @@ At specified intervals (`checkPeriod`), the circuit breaker evaluates `expressio
|
||||
### Open
|
||||
|
||||
While open, the fallback mechanism takes over the normal service calls for a duration of `FallbackDuration`.
|
||||
The fallback mechanism returns a `HTTP 503` (or `ResponseCode`) to the client.
|
||||
After this duration, it enters the recovering state.
|
||||
|
||||
### Recovering
|
||||
@ -191,3 +180,9 @@ The duration for which the circuit breaker will wait before trying to recover (f
|
||||
_Optional, Default="10s"_
|
||||
|
||||
The duration for which the circuit breaker will try to recover (as soon as it is in recovering state).
|
||||
|
||||
### `ResponseCode`
|
||||
|
||||
_Optional, Default="503"_
|
||||
|
||||
The status code that the circuit breaker will return while it is in the open state.
|
||||
|
@ -5,23 +5,24 @@ description: "Traefik Proxy's HTTP middleware lets you compress responses before
|
||||
|
||||
# Compress
|
||||
|
||||
Compress Responses before Sending them to the Client
|
||||
Compress Allows Compressing Responses before Sending them to the Client
|
||||
{: .subtitle }
|
||||
|
||||

|
||||
|
||||
The Compress middleware uses gzip compression.
|
||||
The Compress middleware supports Gzip, Brotli and Zstandard compression.
|
||||
The activation of compression, and the compression method choice rely (among other things) on the request's `Accept-Encoding` header.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Enable gzip compression
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Enable compression
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress=true"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Enable gzip compression
|
||||
# Enable compression
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
@ -31,24 +32,12 @@ spec:
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Enable gzip compression
|
||||
# Enable compression
|
||||
- "traefik.http.middlewares.test-compress.compress=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-compress.compress": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Enable gzip compression
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Enable gzip compression
|
||||
# Enable compression
|
||||
http:
|
||||
middlewares:
|
||||
test-compress:
|
||||
@ -56,7 +45,7 @@ http:
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Enable gzip compression
|
||||
# Enable compression
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-compress.compress]
|
||||
```
|
||||
@ -65,24 +54,39 @@ http:
|
||||
|
||||
Responses are compressed when the following criteria are all met:
|
||||
|
||||
* The response body is larger than the configured minimum amount of bytes (default is `1024`).
|
||||
* The `Accept-Encoding` request header contains `gzip`.
|
||||
* The `Accept-Encoding` request header contains `gzip`, and/or `*`, and/or `br`, and/or `zstd` with or without [quality values](https://developer.mozilla.org/en-US/docs/Glossary/Quality_values).
|
||||
If the `Accept-Encoding` request header is absent and no [defaultEncoding](#defaultencoding) is configured, the response won't be encoded.
|
||||
If it is present, but its value is the empty string, then compression is disabled.
|
||||
* The response is not already compressed, i.e. the `Content-Encoding` response header is not already set.
|
||||
|
||||
If the `Content-Type` header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
||||
It will also set the `Content-Type` header according to the detected MIME type.
|
||||
* The response`Content-Type` header is not one among the [excludedContentTypes options](#excludedcontenttypes), or is one among the [includedContentTypes options](#includedcontenttypes).
|
||||
* The response body is larger than the [configured minimum amount of bytes](#minresponsebodybytes) (default is `1024`).
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `excludedContentTypes`
|
||||
|
||||
_Optional, Default=""_
|
||||
|
||||
`excludedContentTypes` specifies a list of content types to compare the `Content-Type` header of the incoming requests and responses before compressing.
|
||||
|
||||
The responses with content types defined in `excludedContentTypes` are not compressed.
|
||||
|
||||
Content types are compared in a case-insensitive, whitespace-ignored manner.
|
||||
|
||||
```yaml tab="Docker"
|
||||
!!! info
|
||||
|
||||
The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.
|
||||
|
||||
!!! info "In the case of gzip"
|
||||
|
||||
If the `Content-Type` header is not defined, or empty, the compress middleware will automatically [detect](https://mimesniff.spec.whatwg.org/) a content type.
|
||||
It will also set the `Content-Type` header according to the detected MIME type.
|
||||
|
||||
!!! info "gRPC"
|
||||
|
||||
Note that `application/grpc` is never compressed.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.excludedcontenttypes=text/event-stream"
|
||||
```
|
||||
@ -102,17 +106,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-compress.compress.excludedcontenttypes=text/event-stream"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-compress.compress.excludedcontenttypes": "text/event-stream"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.excludedcontenttypes=text/event-stream"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -128,15 +121,74 @@ http:
|
||||
excludedContentTypes = ["text/event-stream"]
|
||||
```
|
||||
|
||||
### `includedContentTypes`
|
||||
|
||||
_Optional, Default=""_
|
||||
|
||||
`includedContentTypes` specifies a list of content types to compare the `Content-Type` header of the responses before compressing.
|
||||
|
||||
The responses with content types defined in `includedContentTypes` are compressed.
|
||||
|
||||
Content types are compared in a case-insensitive, whitespace-ignored manner.
|
||||
|
||||
!!! info
|
||||
|
||||
The `excludedContentTypes` and `includedContentTypes` options are mutually exclusive.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.includedcontenttypes=application/json,text/html,text/plain"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-compress
|
||||
spec:
|
||||
compress:
|
||||
includedContentTypes:
|
||||
- application/json
|
||||
- text/html
|
||||
- text/plain
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-compress.compress.includedcontenttypes=application/json,text/html,text/plain"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-compress:
|
||||
compress:
|
||||
includedContentTypes:
|
||||
- application/json
|
||||
- text/html
|
||||
- text/plain
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-compress.compress]
|
||||
includedContentTypes = ["application/json","text/html","text/plain"]
|
||||
```
|
||||
|
||||
### `minResponseBodyBytes`
|
||||
|
||||
_Optional, Default=1024_
|
||||
|
||||
`minResponseBodyBytes` specifies the minimum amount of bytes a response body must have to be compressed.
|
||||
|
||||
The default value is `1024`, which should be a reasonable value for most cases.
|
||||
|
||||
Responses smaller than the specified values will not be compressed.
|
||||
|
||||
```yaml tab="Docker"
|
||||
!!! tip "Streaming"
|
||||
|
||||
When data is sent to the client on flush, the `minResponseBodyBytes` configuration is ignored and the data is compressed.
|
||||
This is particularly the case when data is streamed to the client when using `Transfer-encoding: chunked` response.
|
||||
|
||||
When chunked data is sent to the client on flush, it will be compressed by default even if the received data has not reached
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.minresponsebodybytes=1200"
|
||||
```
|
||||
@ -155,17 +207,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-compress.compress.minresponsebodybytes=1200"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-compress.compress.minresponsebodybytes": 1200
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.minresponsebodybytes=1200"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -179,3 +220,89 @@ http:
|
||||
[http.middlewares.test-compress.compress]
|
||||
minResponseBodyBytes = 1200
|
||||
```
|
||||
|
||||
### `defaultEncoding`
|
||||
|
||||
_Optional, Default=""_
|
||||
|
||||
`defaultEncoding` specifies the default encoding if the `Accept-Encoding` header is not in the request or contains a wildcard (`*`).
|
||||
|
||||
There is no fallback on the `defaultEncoding` when the header value is empty or unsupported.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.defaultEncoding=gzip"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-compress
|
||||
spec:
|
||||
compress:
|
||||
defaultEncoding: gzip
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-compress.compress.defaultEncoding=gzip"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-compress:
|
||||
compress:
|
||||
defaultEncoding: gzip
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-compress.compress]
|
||||
defaultEncoding = "gzip"
|
||||
```
|
||||
|
||||
### `encodings`
|
||||
|
||||
_Optional, Default="zstd, br, gzip"_
|
||||
|
||||
`encodings` specifies the list of supported compression encodings.
|
||||
At least one encoding value must be specified, and valid entries are `zstd` (Zstandard), `br` (Brotli), and `gzip` (Gzip).
|
||||
The order of the list also sets the priority, the top entry has the highest priority.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-compress.compress.encodings=zstd,br"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-compress
|
||||
spec:
|
||||
compress:
|
||||
encodings:
|
||||
- zstd
|
||||
- br
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-compress.compress.encodings=zstd,br"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-compress:
|
||||
compress:
|
||||
encodings:
|
||||
- zstd
|
||||
- br
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-compress.compress]
|
||||
encodings = ["zstd","br"]
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Traefik ContentType Documentation"
|
||||
description: "Traefik Proxy's HTTP middleware can automatically specify the content-type header if it has not been defined by the backend. Read the technical documentation."
|
||||
description: "Traefik Proxy's HTTP middleware automatically sets the `Content-Type` header value when it is not set by the backend. Read the technical documentation."
|
||||
---
|
||||
|
||||
# ContentType
|
||||
@ -8,84 +8,60 @@ description: "Traefik Proxy's HTTP middleware can automatically specify the cont
|
||||
Handling Content-Type auto-detection
|
||||
{: .subtitle }
|
||||
|
||||
The Content-Type middleware - or rather its `autoDetect` option -
|
||||
specifies whether to let the `Content-Type` header,
|
||||
if it has not been defined by the backend,
|
||||
be automatically set to a value derived from the contents of the response.
|
||||
|
||||
As a proxy, the default behavior should be to leave the header alone,
|
||||
regardless of what the backend did with it.
|
||||
However, the historic default was to always auto-detect and set the header if it was not already defined,
|
||||
and altering this behavior would be a breaking change which would impact many users.
|
||||
|
||||
This middleware exists to enable the correct behavior until at least the default one can be changed in a future version.
|
||||
The Content-Type middleware sets the `Content-Type` header value to the media type detected from the response content,
|
||||
when it is not set by the backend.
|
||||
|
||||
!!! info
|
||||
|
||||
As explained above, for compatibility reasons the default behavior on a router (without this middleware),
|
||||
is still to automatically set the `Content-Type` header.
|
||||
Therefore, given the default value of the `autoDetect` option (false),
|
||||
simply enabling this middleware for a router switches the router's behavior.
|
||||
|
||||
The scope of the Content-Type middleware is the MIME type detection done by the core of Traefik (the server part).
|
||||
Therefore, it has no effect against any other `Content-Type` header modifications (e.g.: in another middleware such as compress).
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Disable auto-detection
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Enable auto-detection
|
||||
labels:
|
||||
- "traefik.http.middlewares.autodetect.contenttype.autodetect=false"
|
||||
- "traefik.http.middlewares.autodetect.contenttype=true"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Disable auto-detection
|
||||
# Enable auto-detection
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: autodetect
|
||||
spec:
|
||||
contentType:
|
||||
autoDetect: false
|
||||
contentType: {}
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Disable auto-detection
|
||||
- "traefik.http.middlewares.autodetect.contenttype.autodetect=false"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.autodetect.contenttype.autodetect": "false"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Disable auto-detection
|
||||
labels:
|
||||
- "traefik.http.middlewares.autodetect.contenttype.autodetect=false"
|
||||
# Enable auto-detection
|
||||
- "traefik.http.middlewares.autodetect.contenttype=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Disable auto-detection
|
||||
# Enable auto-detection
|
||||
http:
|
||||
middlewares:
|
||||
autodetect:
|
||||
contentType:
|
||||
autoDetect: false
|
||||
contentType: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Disable auto-detection
|
||||
# Enable auto-detection
|
||||
[http.middlewares]
|
||||
[http.middlewares.autodetect.contentType]
|
||||
autoDetect=false
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `autoDetect`
|
||||
|
||||
!!! warning
|
||||
|
||||
`autoDetect` option is deprecated and should not be used.
|
||||
Moreover, it is redundant with an empty ContentType middleware declaration.
|
||||
|
||||
`autoDetect` specifies whether to let the `Content-Type` header,
|
||||
if it has not been set by the backend,
|
||||
be automatically set to a value derived from the contents of the response.
|
||||
|
@ -10,11 +10,11 @@ Adding Digest Authentication
|
||||
|
||||

|
||||
|
||||
The DigestAuth middleware restricts access to your services to known users.
|
||||
The DigestAuth middleware grants access to services to authorized users only.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Declaring the user list
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
@ -36,18 +36,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.digestauth.users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Declaring the user list
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Declaring the user list
|
||||
http:
|
||||
@ -84,7 +72,7 @@ The `users` option is an array of authorized users. Each user will be declared u
|
||||
- If both `users` and `usersFile` are provided, the two are merged. The contents of `usersFile` have precedence over the values in `users`.
|
||||
- For security reasons, the field `users` doesn't exist for Kubernetes IngressRoute, and one should use the `secret` field instead.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
@ -114,17 +102,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.digestauth.users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -155,7 +132,7 @@ The file content is a list of `name:realm:encoded-password`.
|
||||
- If both `users` and `usersFile` are provided, the two are merged. The contents of `usersFile` have precedence over the values in `users`.
|
||||
- Because it does not make much sense to refer to a file path on Kubernetes, the `usersFile` field doesn't exist for Kubernetes IngressRoute, and one should use the `secret` field instead.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
@ -186,17 +163,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.digestauth.usersfile": "/path/to/my/usersfile"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.usersfile=/path/to/my/usersfile"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -222,7 +188,7 @@ http:
|
||||
|
||||
You can customize the realm for the authentication with the `realm` option. The default value is `traefik`.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.realm=MyRealm"
|
||||
```
|
||||
@ -241,17 +207,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.realm=MyRealm"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.digestauth.realm": "MyRealm"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.realm=MyRealm"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -270,7 +225,7 @@ http:
|
||||
|
||||
You can customize the header field for the authenticated user using the `headerField`option.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.my-auth.digestauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
@ -290,17 +245,6 @@ spec:
|
||||
- "traefik.http.middlewares.my-auth.digestauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.my-auth.digestauth.headerField": "X-WebAuth-User"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.my-auth.digestauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -320,7 +264,7 @@ http:
|
||||
|
||||
Set the `removeHeader` option to `true` to remove the authorization header before forwarding the request to your service. (Default value is `false`.)
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.removeheader=true"
|
||||
```
|
||||
@ -339,17 +283,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.removeheader=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.digestauth.removeheader": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.digestauth.removeheader=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
|
@ -18,10 +18,10 @@ The Errors middleware returns a custom page in lieu of the default, according to
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Dynamic Custom Error Page for 5XX Status Code
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500-599"
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599"
|
||||
- "traefik.http.middlewares.test-errors.errors.service=serviceError"
|
||||
- "traefik.http.middlewares.test-errors.errors.query=/{status}.html"
|
||||
```
|
||||
@ -34,7 +34,10 @@ metadata:
|
||||
spec:
|
||||
errors:
|
||||
status:
|
||||
- "500-599"
|
||||
- "500"
|
||||
- "501"
|
||||
- "503"
|
||||
- "505-599"
|
||||
query: /{status}.html
|
||||
service:
|
||||
name: whoami
|
||||
@ -42,36 +45,23 @@ spec:
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Dynamic Custom Error Page for 5XX Status Code
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500-599"
|
||||
# Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599"
|
||||
- "traefik.http.middlewares.test-errors.errors.service=serviceError"
|
||||
- "traefik.http.middlewares.test-errors.errors.query=/{status}.html"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-errors.errors.status": "500-599",
|
||||
"traefik.http.middlewares.test-errors.errors.service": "serviceError",
|
||||
"traefik.http.middlewares.test-errors.errors.query": "/{status}.html"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Dynamic Custom Error Page for 5XX Status Code
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-errors.errors.status=500-599"
|
||||
- "traefik.http.middlewares.test-errors.errors.service=serviceError"
|
||||
- "traefik.http.middlewares.test-errors.errors.query=/{status}.html"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Custom Error Page for 5XX
|
||||
# Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
http:
|
||||
middlewares:
|
||||
test-errors:
|
||||
errors:
|
||||
status:
|
||||
- "500-599"
|
||||
- "500"
|
||||
- "501"
|
||||
- "503"
|
||||
- "505-599"
|
||||
service: serviceError
|
||||
query: "/{status}.html"
|
||||
|
||||
@ -80,10 +70,10 @@ http:
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Custom Error Page for 5XX
|
||||
# Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-errors.errors]
|
||||
status = ["500-599"]
|
||||
status = ["500","501","503","505-599"]
|
||||
service = "serviceError"
|
||||
query = "/{status}.html"
|
||||
|
||||
@ -101,14 +91,29 @@ http:
|
||||
|
||||
The `status` option defines which status or range of statuses should result in an error page.
|
||||
|
||||
The status code ranges are inclusive (`500-599` will trigger with every code between `500` and `599`, `500` and `599` included).
|
||||
The status code ranges are inclusive (`505-599` will trigger with every code between `505` and `599`, `505` and `599` included).
|
||||
|
||||
!!! note ""
|
||||
|
||||
You can define either a status code as a number (`500`),
|
||||
as multiple comma-separated numbers (`500,502`),
|
||||
as ranges by separating two codes with a dash (`500-599`),
|
||||
or a combination of the two (`404,418,500-599`).
|
||||
as ranges by separating two codes with a dash (`505-599`),
|
||||
or a combination of the two (`404,418,505-599`).
|
||||
The comma-separated syntax is only available for label-based providers.
|
||||
The examples above demonstrate which syntax is appropriate for each provider.
|
||||
|
||||
### `statusRewrites`
|
||||
|
||||
An optional mapping of status codes to be rewritten. For example, if a service returns a 418, you might want to rewrite it to a 404.
|
||||
You can map individual status codes or even ranges to a different status code. The syntax for ranges follows the same rules as the `status` option.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```yml
|
||||
statusRewrites:
|
||||
"500-503": 500
|
||||
"418": 404
|
||||
```
|
||||
|
||||
### `service`
|
||||
|
||||
@ -131,7 +136,8 @@ There are multiple variables that can be placed in the `query` option to insert
|
||||
|
||||
The table below lists all the available variables and their associated values.
|
||||
|
||||
| Variable | Value |
|
||||
|------------|--------------------------------------------------------------------|
|
||||
| `{status}` | The response status code. |
|
||||
| `{url}` | The [escaped](https://pkg.go.dev/net/url#QueryEscape) request URL. |
|
||||
| Variable | Value |
|
||||
|--------------------|--------------------------------------------------------------------------------------------|
|
||||
| `{status}` | The response status code. It may be rewritten when using the `statusRewrites` option. |
|
||||
| `{originalStatus}` | The original response status code, if it has been modified by the `statusRewrites` option. |
|
||||
| `{url}` | The [escaped](https://pkg.go.dev/net/url#QueryEscape) request URL. |
|
||||
|
@ -16,7 +16,7 @@ Otherwise, the response from the authentication server is returned.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Forward authentication to example.com
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
@ -38,18 +38,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.address": "https://example.com/auth"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Forward authentication to example.com
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Forward authentication to example.com
|
||||
http:
|
||||
@ -84,7 +72,7 @@ The following request properties are provided to the forward-auth target endpoin
|
||||
|
||||
The `address` option defines the authentication server address.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
@ -103,17 +91,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.address": "https://example.com/auth"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -132,7 +109,7 @@ http:
|
||||
|
||||
Set the `trustForwardHeader` option to `true` to trust all `X-Forwarded-*` headers.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader=true"
|
||||
```
|
||||
@ -152,17 +129,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -184,7 +150,7 @@ http:
|
||||
The `authResponseHeaders` option is the list of headers to copy from the authentication server response and set on
|
||||
forwarded request, replacing any existing conflicting headers.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders=X-Auth-User, X-Secret"
|
||||
```
|
||||
@ -206,17 +172,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders=X-Auth-User, X-Secret"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders": "X-Auth-User,X-Secret"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders=X-Auth-User, X-Secret"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -242,7 +197,7 @@ set on forwarded request, after stripping all headers that match the regex.
|
||||
It allows partial matching of the regular expression against the header key.
|
||||
The start of string (`^`) and end of string (`$`) anchors should be used to ensure a full match against the header key.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
@ -262,17 +217,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex": "^X-"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -301,7 +245,7 @@ The `authRequestHeaders` option is the list of the headers to copy from the requ
|
||||
It allows filtering headers that should not be passed to the authentication server.
|
||||
If not set or empty then all request headers are passed.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders=Accept,X-CustomHeader"
|
||||
```
|
||||
@ -323,17 +267,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders=Accept,X-CustomHeader"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders": "Accept,X-CustomHeader"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders=Accept,X-CustomHeader"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -352,6 +285,147 @@ http:
|
||||
authRequestHeaders = "Accept,X-CustomHeader"
|
||||
```
|
||||
|
||||
### `addAuthCookiesToResponse`
|
||||
|
||||
The `addAuthCookiesToResponse` option is the list of cookies to copy from the authentication server to the response,
|
||||
replacing any existing conflicting cookie from the forwarded response.
|
||||
|
||||
!!! info
|
||||
|
||||
Please note that all backend cookies matching the configured list will not be added to the response.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.addAuthCookiesToResponse=Session-Cookie,State-Cookie"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://example.com/auth
|
||||
addAuthCookiesToResponse:
|
||||
- Session-Cookie
|
||||
- State-Cookie
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.addAuthCookiesToResponse=Session-Cookie,State-Cookie"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://example.com/auth"
|
||||
addAuthCookiesToResponse:
|
||||
- "Session-Cookie"
|
||||
- "State-Cookie"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://example.com/auth"
|
||||
addAuthCookiesToResponse = ["Session-Cookie", "State-Cookie"]
|
||||
```
|
||||
|
||||
### `forwardBody`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
Set the `forwardBody` option to `true` to send Body.
|
||||
|
||||
!!! info
|
||||
|
||||
As body is read inside Traefik before forwarding, this breaks streaming.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.forwardBody=true"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://example.com/auth
|
||||
forwardBody: true
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.forwardBody=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://example.com/auth"
|
||||
forwardBody: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://example.com/auth"
|
||||
forwardBody = true
|
||||
```
|
||||
|
||||
### `maxBodySize`
|
||||
|
||||
_Optional, Default=-1_
|
||||
|
||||
Set the `maxBodySize` to limit the body size in bytes.
|
||||
If body is bigger than this, it returns a 401 (unauthorized).
|
||||
Default is `-1`, which means no limit.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.maxBodySize=1000"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://example.com/auth
|
||||
forwardBody: true
|
||||
maxBodySize: 1000
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.maxBodySize=1000"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://example.com/auth"
|
||||
maxBodySize: 1000
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://example.com/auth"
|
||||
forwardBody = true
|
||||
maxBodySize = 1000
|
||||
```
|
||||
|
||||
### `tls`
|
||||
|
||||
_Optional_
|
||||
@ -365,7 +439,7 @@ _Optional_
|
||||
`ca` is the path to the certificate authority used for the secured connection to the authentication server,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.ca=path/to/local.crt"
|
||||
```
|
||||
@ -397,17 +471,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.ca=path/to/local.crt"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.ca": "path/to/local.crt"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.ca=path/to/local.crt"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -433,7 +496,7 @@ _Optional_
|
||||
`cert` is the path to the public certificate used for the secure connection to the authentication server.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.cert=path/to/foo.cert"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
@ -467,19 +530,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.cert": "path/to/foo.cert",
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.key": "path/to/foo.key"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.cert=path/to/foo.cert"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -511,7 +561,7 @@ _Optional_
|
||||
`key` is the path to the private key used for the secure connection to the authentication server.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.cert=path/to/foo.cert"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
@ -545,19 +595,6 @@ data:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.cert": "path/to/foo.cert",
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.key": "path/to/foo.key"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.cert=path/to/foo.cert"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -588,7 +625,7 @@ _Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`, the TLS connection to the authentication server accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.insecureSkipVerify=true"
|
||||
```
|
||||
@ -609,17 +646,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.InsecureSkipVerify=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.tls.insecureSkipVerify": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.tls.InsecureSkipVerify=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -637,3 +663,128 @@ http:
|
||||
[http.middlewares.test-auth.forwardAuth.tls]
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
### `headerField`
|
||||
|
||||
_Optional_
|
||||
|
||||
You can define a header field to store the authenticated user using the `headerField`option.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
# ...
|
||||
headerField: X-WebAuth-User
|
||||
```
|
||||
|
||||
```json tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.headerField=X-WebAuth-User"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
# ...
|
||||
headerField: "X-WebAuth-User"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
# ...
|
||||
headerField = "X-WebAuth-User"
|
||||
```
|
||||
|
||||
### `preserveLocationHeader`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
`preserveLocationHeader` defines whether to forward the `Location` header to the client as is or prefix it with the domain name of the authentication server.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.preserveLocationHeader=true"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
# ...
|
||||
preserveLocationHeader: true
|
||||
```
|
||||
|
||||
```json tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.preserveLocationHeader=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
# ...
|
||||
preserveLocationHeader: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
# ...
|
||||
preserveLocationHeader = true
|
||||
```
|
||||
|
||||
### `preserveRequestMethod`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
`preserveRequestMethod` defines whether to preserve the original request method while forwarding the request to the authentication server. By default, when this option is set to `false`, incoming requests are always forwarded as `GET` requests to the authentication server.
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.preserveRequestMethod=true"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
# ...
|
||||
preserveRequestMethod: true
|
||||
```
|
||||
|
||||
```json tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.preserveRequestMethod=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
# ...
|
||||
preserveRequestMethod: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
# ...
|
||||
preserveRequestMethod = true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
66
docs/content/middlewares/http/grpcweb.md
Normal file
66
docs/content/middlewares/http/grpcweb.md
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
title: "Traefik GrpcWeb Documentation"
|
||||
description: "In Traefik Proxy's HTTP middleware, GrpcWeb converts a gRPC Web requests to HTTP/2 gRPC requests. Read the technical documentation."
|
||||
---
|
||||
|
||||
# GrpcWeb
|
||||
|
||||
Converting gRPC Web requests to HTTP/2 gRPC requests.
|
||||
{: .subtitle }
|
||||
|
||||
The GrpcWeb middleware converts gRPC Web requests to HTTP/2 gRPC requests before forwarding them to the backends.
|
||||
|
||||
!!! tip
|
||||
|
||||
Please note, that Traefik needs to communicate using gRPC with the backends (h2c or HTTP/2 over TLS).
|
||||
Check out the [gRPC](../../user-guides/grpc.md) user guide for more details.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-grpcweb.grpcweb.allowOrigins=*"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-grpcweb
|
||||
spec:
|
||||
grpcWeb:
|
||||
allowOrigins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-grpcweb.grpcWeb.allowOrigins=*"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-grpcweb:
|
||||
grpcWeb:
|
||||
allowOrigins:
|
||||
- "*"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-grpcweb.grpcWeb]
|
||||
allowOrigins = ["*"]
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `allowOrigins`
|
||||
|
||||
The `allowOrigins` contains the list of allowed origins.
|
||||
A wildcard origin `*` can also be configured to match all requests.
|
||||
|
||||
More information including how to use the settings can be found at:
|
||||
|
||||
- [Mozilla.org](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)
|
||||
- [w3](https://fetch.spec.whatwg.org/#http-access-control-allow-origin)
|
||||
- [IETF](https://tools.ietf.org/html/rfc6454#section-7.1)
|
@ -20,7 +20,7 @@ A set of forwarded headers are automatically added by default. See the [FAQ](../
|
||||
|
||||
The following example adds the `X-Script-Name` header to the proxied request and the `X-Custom-Response-Header` header to the response
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testHeader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testHeader.headers.customresponseheaders.X-Custom-Response-Header=value"
|
||||
@ -44,19 +44,6 @@ spec:
|
||||
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name": "test",
|
||||
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header": "value"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -82,7 +69,7 @@ http:
|
||||
In the following example, requests are proxied with an extra `X-Script-Name` header while their `X-Custom-Request-Header` header gets stripped,
|
||||
and responses are stripped of their `X-Custom-Response-Header` header.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header="
|
||||
@ -109,21 +96,6 @@ spec:
|
||||
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name": "test",
|
||||
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header": "",
|
||||
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header": "",
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"
|
||||
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header="
|
||||
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -151,7 +123,7 @@ http:
|
||||
Security-related headers (HSTS headers, Browser XSS filter, etc) can be managed similarly to custom headers as shown above.
|
||||
This functionality makes it possible to easily use security features by adding headers.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testHeader.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.testHeader.headers.browserxssfilter=true"
|
||||
@ -173,19 +145,6 @@ spec:
|
||||
- "traefik.http.middlewares.testheader.headers.browserxssfilter=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.framedeny": "true",
|
||||
"traefik.http.middlewares.testheader.headers.browserxssfilter": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.framedeny=true"
|
||||
- "traefik.http.middlewares.testheader.headers.browserxssfilter=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -211,7 +170,7 @@ instead the response will be generated and sent back to the client directly.
|
||||
Please note that the example below is by no means authoritative or exhaustive,
|
||||
and should not be used as is for production.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*"
|
||||
@ -231,7 +190,8 @@ spec:
|
||||
- "GET"
|
||||
- "OPTIONS"
|
||||
- "PUT"
|
||||
accessControlAllowHeaders: "*"
|
||||
accessControlAllowHeaders:
|
||||
- "*"
|
||||
accessControlAllowOriginList:
|
||||
- "https://foo.bar.org"
|
||||
- "https://example.org"
|
||||
@ -247,25 +207,6 @@ spec:
|
||||
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolallowmethods": "GET,OPTIONS,PUT",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist": "https://foo.bar.org,https://example.org",
|
||||
"traefik.http.middlewares.testheader.headers.accesscontrolmaxage": "100",
|
||||
"traefik.http.middlewares.testheader.headers.addvaryheader": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org"
|
||||
- "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
|
||||
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -286,8 +227,8 @@ http:
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.testHeader.headers]
|
||||
accessControlAllowMethods= ["GET", "OPTIONS", "PUT"]
|
||||
accessControlAllowHeaders= "*"
|
||||
accessControlAllowMethods = ["GET", "OPTIONS", "PUT"]
|
||||
accessControlAllowHeaders = [ "*" ]
|
||||
accessControlAllowOriginList = ["https://foo.bar.org","https://example.org"]
|
||||
accessControlMaxAge = 100
|
||||
addVaryHeader = true
|
||||
@ -453,6 +394,10 @@ This overrides the `BrowserXssFilter` option.
|
||||
|
||||
The `contentSecurityPolicy` option allows the `Content-Security-Policy` header value to be set with a custom value.
|
||||
|
||||
### `contentSecurityPolicyReportOnly`
|
||||
|
||||
The `contentSecurityPolicyReportOnly` option allows the `Content-Security-Policy-Report-Only` header value to be set with a custom value.
|
||||
|
||||
### `publicKey`
|
||||
|
||||
The `publicKey` implements HPKP to prevent MITM attacks with forged certificates.
|
||||
@ -465,7 +410,7 @@ The `referrerPolicy` allows sites to control whether browsers forward the `Refer
|
||||
|
||||
!!! warning
|
||||
|
||||
Deprecated in favor of `permissionsPolicy`
|
||||
Deprecated in favor of [`permissionsPolicy`](#permissionsPolicy)
|
||||
|
||||
The `featurePolicy` allows sites to control browser features.
|
||||
|
||||
|
@ -14,7 +14,7 @@ To proactively prevent services from being overwhelmed with high load, the numbe
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
@ -34,18 +34,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.amount": "10"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Limiting to 10 simultaneous connections
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
http:
|
||||
@ -69,7 +57,7 @@ http:
|
||||
The `amount` option defines the maximum amount of allowed simultaneous in-flight request.
|
||||
The middleware responds with `HTTP 429 Too Many Requests` if there are already `amount` requests in progress (based on the same `sourceCriterion` strategy).
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
@ -89,18 +77,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.amount": "10"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Limiting to 10 simultaneous connections
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Limiting to 10 simultaneous connections
|
||||
http:
|
||||
@ -125,7 +101,7 @@ If none are set, the default is to use the `requestHost`.
|
||||
|
||||
#### `sourceCriterion.ipStrategy`
|
||||
|
||||
The `ipStrategy` option defines two parameters that configures how Traefik determines the client IP: `depth`, and `excludedIPs`.
|
||||
The `ipStrategy` option defines three parameters that configures how Traefik determines the client IP: `depth`, `excludedIPs` and `ipv6Subnet`.
|
||||
|
||||
!!! important "As a middleware, InFlightReq happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through the middleware. Therefore, during InFlightReq, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be used and/or relied upon."
|
||||
|
||||
@ -136,6 +112,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and select
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty.
|
||||
- `depth` is ignored if its value is less than or equal to 0.
|
||||
|
||||
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||
|
||||
!!! example "Example of Depth & X-Forwarded-For"
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||
@ -146,7 +125,7 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and select
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth=2"
|
||||
```
|
||||
@ -167,17 +146,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth": "2"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -211,7 +179,7 @@ http:
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
@ -234,17 +202,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -264,11 +221,68 @@ http:
|
||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
##### `ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||
|
||||
!!! example "Example of ipv6Subnet"
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| `IP` | `ipv6Subnet` | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-inflightreq
|
||||
spec:
|
||||
inFlightReq:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-inflightreq:
|
||||
inFlightReq:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-inflightreq.inflightreq]
|
||||
[http.middlewares.test-inflightreq.inFlightReq.sourceCriterion.ipStrategy]
|
||||
ipv6Subnet = 64
|
||||
```
|
||||
|
||||
#### `sourceCriterion.requestHeaderName`
|
||||
|
||||
Name of the header used to group incoming requests.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername=username"
|
||||
```
|
||||
@ -288,17 +302,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername=username"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername": "username"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername=username"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -319,7 +322,7 @@ http:
|
||||
|
||||
Whether to consider the request host as the source.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true"
|
||||
```
|
||||
@ -335,21 +338,10 @@ spec:
|
||||
requestHost: true
|
||||
```
|
||||
|
||||
```yaml tab="Cosul Catalog"
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
|
266
docs/content/middlewares/http/ipallowlist.md
Normal file
266
docs/content/middlewares/http/ipallowlist.md
Normal file
@ -0,0 +1,266 @@
|
||||
---
|
||||
title: "Traefik HTTP Middlewares IPAllowList"
|
||||
description: "Learn how to use IPAllowList in HTTP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
# IPAllowList
|
||||
|
||||
Limiting Clients to Specific IPs
|
||||
{: .subtitle }
|
||||
|
||||
IPAllowList limits allowed requests based on the client IP.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Accepts request from defined IP
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Accepts request from defined IP
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Accepts request from defined IP
|
||||
http:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Accepts request from defined IP
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `sourceRange`
|
||||
|
||||
_Required_
|
||||
|
||||
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||
|
||||
### `ipStrategy`
|
||||
|
||||
The `ipStrategy` option defines two parameters that set how Traefik determines the client IP: `depth`, and `excludedIPs`.
|
||||
If no strategy is set, the default behavior is to match `sourceRange` against the Remote address found in the request.
|
||||
|
||||
!!! important "As a middleware, whitelisting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through whitelisting. Therefore, during whitelisting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be matched against `sourceRange`."
|
||||
|
||||
#### `ipStrategy.depth`
|
||||
|
||||
The `depth` option tells Traefik to use the `X-Forwarded-For` header and take the IP located at the `depth` position (starting from the right).
|
||||
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is less than or equal to 0.
|
||||
|
||||
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||
|
||||
!!! example "Examples of Depth & X-Forwarded-For"
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used is `"12.0.0.1"` (`depth=2`).
|
||||
|
||||
| `X-Forwarded-For` | `depth` | clientIP |
|
||||
|-----------------------------------------|---------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `1` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` |
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
ipStrategy:
|
||||
depth: 2
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
|
||||
http:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
ipStrategy:
|
||||
depth: 2
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList.ipStrategy]
|
||||
depth = 2
|
||||
```
|
||||
|
||||
#### `ipStrategy.excludedIPs`
|
||||
|
||||
`excludedIPs` configures Traefik to scan the `X-Forwarded-For` header and select the first IP not in the list.
|
||||
|
||||
!!! important "If `depth` is specified, `excludedIPs` is ignored."
|
||||
|
||||
!!! example "Example of ExcludedIPs & X-Forwarded-For"
|
||||
|
||||
| `X-Forwarded-For` | `excludedIPs` | clientIP |
|
||||
|-----------------------------------------|-----------------------|--------------|
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"12.0.0.1,13.0.0.1"` | `"11.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"10.0.0.1,13.0.0.1"` | `"12.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` |
|
||||
| `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` |
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.0/24
|
||||
ipStrategy:
|
||||
excludedIPs:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
http:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.0/24
|
||||
ipStrategy:
|
||||
excludedIPs:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.0/24"]
|
||||
[http.middlewares.test-ipallowlist.ipAllowList.ipStrategy]
|
||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
#### `ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||
|
||||
!!! example "Example of ipv6Subnet"
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| `IP` | `ipv6Subnet` | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipallowlist:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipallowlist:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipallowlist.ipallowlist]
|
||||
[http.middlewares.test-ipallowlist.ipallowlist.sourceCriterion.ipStrategy]
|
||||
ipv6Subnet = 64
|
||||
```
|
@ -8,9 +8,13 @@ description: "Learn how to use IPWhiteList in HTTP middleware for limiting clien
|
||||
Limiting Clients to Specific IPs
|
||||
{: .subtitle }
|
||||
|
||||

|
||||

|
||||
|
||||
IPWhitelist accepts / refuses requests based on the client IP.
|
||||
IPWhiteList limits allowed requests based on the client IP.
|
||||
|
||||
!!! warning
|
||||
|
||||
This middleware is deprecated, please use the [IPAllowList](./ipallowlist.md) middleware instead.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
@ -37,18 +41,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange": "127.0.0.1/32,192.168.1.7"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Accepts request from defined IP
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Accepts request from defined IP
|
||||
http:
|
||||
@ -71,6 +63,8 @@ http:
|
||||
|
||||
### `sourceRange`
|
||||
|
||||
_Required_
|
||||
|
||||
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||
|
||||
### `ipStrategy`
|
||||
@ -87,6 +81,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||
- `depth` is ignored if its value is less than or equal to 0.
|
||||
|
||||
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||
|
||||
!!! example "Examples of Depth & X-Forwarded-For"
|
||||
|
||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used for the whitelisting is `"12.0.0.1"` (`depth=2`).
|
||||
@ -125,20 +122,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange": "127.0.0.1/32, 192.168.1.7",
|
||||
"traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.depth": "2"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.depth=2"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Whitelisting Based on `X-Forwarded-For` with `depth=2`
|
||||
http:
|
||||
@ -180,6 +163,7 @@ http:
|
||||
```yaml tab="Docker"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
@ -192,6 +176,9 @@ metadata:
|
||||
spec:
|
||||
ipWhiteList:
|
||||
ipStrategy:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.0/24
|
||||
excludedIPs:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
@ -199,37 +186,87 @@ spec:
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24"
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
http:
|
||||
middlewares:
|
||||
test-ipwhitelist:
|
||||
ipWhiteList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.0/24
|
||||
ipStrategy:
|
||||
excludedIPs:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Exclude from `X-Forwarded-For`
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.0/24"]
|
||||
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
#### `ipStrategy.ipv6Subnet`
|
||||
|
||||
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||
|
||||
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||
|
||||
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||
|
||||
!!! example "Example of ipv6Subnet"
|
||||
|
||||
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||
|
||||
| `IP` | `ipv6Subnet` | clientIP |
|
||||
|---------------------------|--------------|-----------------------|
|
||||
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-ipWhiteList.ipWhiteList.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-ipWhiteList
|
||||
spec:
|
||||
ipWhiteList:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-ipWhiteList.ipWhiteList.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-ipWhiteList:
|
||||
ipWhiteList:
|
||||
sourceCriterion:
|
||||
ipStrategy:
|
||||
ipv6Subnet: 64
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-ipWhiteList.ipWhiteList]
|
||||
[http.middlewares.test-ipWhiteList.ipWhiteList.sourceCriterion.ipStrategy]
|
||||
ipv6Subnet = 64
|
||||
```
|
||||
|
@ -12,7 +12,7 @@ Controlling connections
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# As a Docker Label
|
||||
whoami:
|
||||
# A container that exposes an API to show its IP address
|
||||
@ -24,21 +24,8 @@ whoami:
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
# As a Kubernetes Traefik IngressRoute
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: middlewares.traefik.io
|
||||
spec:
|
||||
group: traefik.io
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: Middleware
|
||||
plural: middlewares
|
||||
singular: middleware
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
@ -69,22 +56,6 @@ spec:
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@consulcatalog"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.foo-add-prefix.addprefix.prefix": "/foo",
|
||||
"traefik.http.routers.router1.middlewares": "foo-add-prefix@marathon"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# As a Rancher Label
|
||||
labels:
|
||||
# Create a middleware named `foo-add-prefix`
|
||||
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
|
||||
# Apply the middleware named `foo-add-prefix` to the router named `router1`
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@rancher"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# As TOML Configuration File
|
||||
[http.routers]
|
||||
@ -142,7 +113,7 @@ http:
|
||||
| [Errors](errorpages.md) | Defines custom error pages | Request Lifecycle |
|
||||
| [ForwardAuth](forwardauth.md) | Delegates Authentication | Security, Authentication |
|
||||
| [Headers](headers.md) | Adds / Updates headers | Security |
|
||||
| [IPWhiteList](ipwhitelist.md) | Limits the allowed client IPs | Security, Request lifecycle |
|
||||
| [IPAllowList](ipallowlist.md) | Limits the allowed client IPs | Security, Request lifecycle |
|
||||
| [InFlightReq](inflightreq.md) | Limits the number of simultaneous connections | Security, Request lifecycle |
|
||||
| [PassTLSClientCert](passtlsclientcert.md) | Adds Client Certificates in a Header | Security |
|
||||
| [RateLimit](ratelimit.md) | Limits the call frequency | Security, Request lifecycle |
|
||||
|
@ -18,7 +18,7 @@ PassTLSClientCert adds the selected data from the passed client TLS certificate
|
||||
|
||||
Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
|
||||
@ -39,18 +39,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||
http:
|
||||
@ -69,7 +57,7 @@ http:
|
||||
|
||||
??? example "Pass the pem in the `X-Forwarded-Tls-Client-Cert` header"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
||||
@ -146,52 +134,6 @@ http:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province": "true",
|
||||
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||
http:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ The RedirectRegex redirects a request using regex matching and replacement.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Redirect with domain replacement
|
||||
# Note: all dollar signs need to be doubled for escaping.
|
||||
labels:
|
||||
@ -43,21 +43,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-redirectregex.redirectregex.regex": "^http://localhost/(.*)",
|
||||
"traefik.http.middlewares.test-redirectregex.redirectregex.replacement": "http://mydomain/${1}"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Redirect with domain replacement
|
||||
# Note: all dollar signs need to be doubled for escaping.
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
|
||||
- "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Redirect with domain replacement
|
||||
http:
|
||||
@ -99,3 +84,5 @@ The `replacement` option defines how to modify the URL to have the new target UR
|
||||
!!! warning
|
||||
|
||||
Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -25,7 +25,7 @@ The RedirectScheme middleware redirects the request if the request scheme is dif
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Redirect to https
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
@ -51,20 +51,6 @@ labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme": "https"
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Redirect to https
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Redirect to https
|
||||
http:
|
||||
@ -89,7 +75,7 @@ http:
|
||||
|
||||
Set the `permanent` option to `true` to apply a permanent redirection.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Redirect to https
|
||||
labels:
|
||||
# ...
|
||||
@ -115,20 +101,6 @@ labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent": "true"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Redirect to https
|
||||
labels:
|
||||
# ...
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Redirect to https
|
||||
http:
|
||||
@ -151,7 +123,7 @@ http:
|
||||
|
||||
The `scheme` option defines the scheme of the new URL.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Redirect to https
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
@ -174,18 +146,6 @@ labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme": "https"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Redirect to https
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Redirect to https
|
||||
http:
|
||||
@ -206,7 +166,7 @@ http:
|
||||
|
||||
The `port` option defines the port of the new URL.
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Redirect to https
|
||||
labels:
|
||||
# ...
|
||||
@ -232,20 +192,6 @@ labels:
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.port=443"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
|
||||
"traefik.http.middlewares.test-redirectscheme.redirectscheme.port": "443"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Redirect to https
|
||||
labels:
|
||||
# ...
|
||||
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.port=443"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Redirect to https
|
||||
http:
|
||||
|
@ -16,7 +16,7 @@ Replace the path of the request URL.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Replace the path with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||
@ -38,18 +38,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-replacepath.replacepath.path": "/foo"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Replace the path with /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Replace the path with /foo
|
||||
http:
|
||||
|
@ -16,7 +16,7 @@ The ReplaceRegex replaces the path of a URL using regex matching and replacement
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Replace path with regex
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)"
|
||||
@ -41,20 +41,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$1"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-replacepathregex.replacepathregex.regex": "^/foo/(.*)",
|
||||
"traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement": "/bar/$1"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Replace path with regex
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)"
|
||||
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$1"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Replace path with regex
|
||||
http:
|
||||
|
@ -18,7 +18,7 @@ The Retry middleware has an optional configuration to enable an exponential back
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Retry 4 times with exponential backoff
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-retry.retry.attempts=4"
|
||||
@ -43,20 +43,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-retry.retry.initialinterval=100ms"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-retry.retry.attempts": "4",
|
||||
"traefik.http.middlewares.test-retry.retry.initialinterval": "100ms",
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Retry 4 times with exponential backoff
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-retry.retry.attempts=4"
|
||||
- "traefik.http.middlewares.test-retry.retry.initialinterval=100ms"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Retry 4 times with exponential backoff
|
||||
http:
|
||||
|
@ -16,7 +16,7 @@ Remove the specified prefixes from the URL path.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
|
||||
@ -40,18 +40,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-stripprefix.stripprefix.prefixes": "/foobar,/fiibar"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Strip prefix /foobar and /fiibar
|
||||
http:
|
||||
@ -93,12 +81,12 @@ Using the previous example, the backend should return `/products/shoes/image.png
|
||||
|
||||
_Optional, Default=true_
|
||||
|
||||
!!! warning
|
||||
|
||||
`forceSlash` option is deprecated and should not be used.
|
||||
|
||||
The `forceSlash` option ensures the resulting stripped path is not the empty string, by replacing it with `/` when necessary.
|
||||
|
||||
This option was added to keep the initial (non-intuitive) behavior of this middleware, in order to avoid introducing a breaking change.
|
||||
|
||||
It is recommended to explicitly set `forceSlash` to `false`.
|
||||
|
||||
??? info "Behavior examples"
|
||||
|
||||
- `forceSlash=true`
|
||||
@ -141,19 +129,6 @@ spec:
|
||||
forceSlash: false
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.example.stripprefix.prefixes": "/foobar",
|
||||
"traefik.http.middlewares.example.stripprefix.forceSlash": "false"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.example.stripprefix.prefixes=/foobar"
|
||||
- "traefik.http.middlewares.example.stripprefix.forceSlash=false"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
@ -170,3 +145,5 @@ http:
|
||||
prefixes = ["/foobar"]
|
||||
forceSlash = false
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -12,7 +12,7 @@ Remove the matching prefixes from the URL path.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
@ -32,17 +32,6 @@ spec:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "/foo/[a-z0-9]+/[0-9]+/"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
|
@ -23,7 +23,7 @@ Middlewares that use the same protocol can be combined into chains to fit every
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# As a Docker Label
|
||||
whoami:
|
||||
# A container that exposes an API to show its IP address
|
||||
@ -35,7 +35,7 @@ whoami:
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
@ -66,22 +66,6 @@ spec:
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@consulcatalog"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.foo-add-prefix.addprefix.prefix": "/foo",
|
||||
"traefik.http.routers.router1.middlewares": "foo-add-prefix@marathon"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# As a Rancher Label
|
||||
labels:
|
||||
# Create a middleware named `foo-add-prefix`
|
||||
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
|
||||
# Apply the middleware named `foo-add-prefix` to the router named `router1`
|
||||
- "traefik.http.routers.router1.middlewares=foo-add-prefix@rancher"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# As YAML Configuration File
|
||||
http:
|
||||
|
@ -7,7 +7,7 @@ To proactively prevent services from being overwhelmed with high load, the numbe
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
|
||||
```
|
||||
@ -27,18 +27,6 @@ spec:
|
||||
- "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.tcp.middlewares.test-inflightconn.inflightconn.amount": "10"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Limiting to 10 simultaneous connections.
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Limiting to 10 simultaneous connections.
|
||||
tcp:
|
||||
|
60
docs/content/middlewares/tcp/ipallowlist.md
Normal file
60
docs/content/middlewares/tcp/ipallowlist.md
Normal file
@ -0,0 +1,60 @@
|
||||
---
|
||||
title: "Traefik TCP Middlewares IPAllowList"
|
||||
description: "Learn how to use IPAllowList in TCP middleware for limiting clients to specific IPs in Traefik Proxy. Read the technical documentation."
|
||||
---
|
||||
|
||||
# IPAllowList
|
||||
|
||||
Limiting Clients to Specific IPs
|
||||
{: .subtitle }
|
||||
|
||||
IPAllowList limits allowed requests based on the client IP.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker & Swarm"
|
||||
# Accepts connections from defined IP
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: test-ipallowlist
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Accepts request from defined IP
|
||||
- "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Accepts request from defined IP
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.test-ipallowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Accepts request from defined IP
|
||||
tcp:
|
||||
middlewares:
|
||||
test-ipallowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `sourceRange`
|
||||
|
||||
The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
@ -8,7 +8,11 @@ description: "Learn how to use IPWhiteList in TCP middleware for limiting client
|
||||
Limiting Clients to Specific IPs
|
||||
{: .subtitle }
|
||||
|
||||
IPWhitelist accepts / refuses connections based on the client IP.
|
||||
IPWhiteList accepts / refuses connections based on the client IP.
|
||||
|
||||
!!! warning
|
||||
|
||||
This middleware is deprecated, please use the [IPAllowList](./ipallowlist.md) middleware instead.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
@ -35,18 +39,6 @@ spec:
|
||||
- "traefik.tcp.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.tcp.middlewares.test-ipwhitelist.ipwhitelist.sourcerange": "127.0.0.1/32,192.168.1.7"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Accepts request from defined IP
|
||||
labels:
|
||||
- "traefik.tcp.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Accepts request from defined IP
|
||||
[tcp.middlewares]
|
||||
|
@ -12,40 +12,27 @@ Controlling connections
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# As a Docker Label
|
||||
whoami:
|
||||
# A container that exposes an API to show its IP address
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
# Create a middleware named `foo-ip-whitelist`
|
||||
- "traefik.tcp.middlewares.foo-ip-whitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-whitelist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-whitelist@docker"
|
||||
# Create a middleware named `foo-ip-allowlist`
|
||||
- "traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-allowlist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@docker"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
# As a Kubernetes Traefik IngressRoute
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: middlewaretcps.traefik.io
|
||||
spec:
|
||||
group: traefik.io
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: MiddlewareTCP
|
||||
plural: middlewaretcps
|
||||
singular: middlewaretcp
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: foo-ip-whitelist
|
||||
name: foo-ip-allowlist
|
||||
spec:
|
||||
ipWhiteList:
|
||||
ipAllowList:
|
||||
sourcerange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.7
|
||||
@ -60,30 +47,14 @@ spec:
|
||||
routes:
|
||||
# more fields...
|
||||
middlewares:
|
||||
- name: foo-ip-whitelist
|
||||
- name: foo-ip-allowlist
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
# Create a middleware named `foo-ip-whitelist`
|
||||
- "traefik.tcp.middlewares.foo-ip-whitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-whitelist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-whitelist@consulcatalog"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.tcp.middlewares.foo-ip-whitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7",
|
||||
"traefik.tcp.routers.router1.middlewares=foo-ip-whitelist@marathon"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# As a Rancher Label
|
||||
labels:
|
||||
# Create a middleware named `foo-ip-whitelist`
|
||||
- "traefik.tcp.middlewares.foo-ip-whitelist.ipwhitelist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-whitelist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-whitelist@rancher"
|
||||
# Create a middleware named `foo-ip-allowlist`
|
||||
- "traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
|
||||
# Apply the middleware named `foo-ip-allowlist` to the router named `router1`
|
||||
- "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@consulcatalog"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@ -91,11 +62,11 @@ labels:
|
||||
[tcp.routers]
|
||||
[tcp.routers.router1]
|
||||
service = "myService"
|
||||
middlewares = ["foo-ip-whitelist"]
|
||||
middlewares = ["foo-ip-allowlist"]
|
||||
rule = "Host(`example.com`)"
|
||||
|
||||
[tcp.middlewares]
|
||||
[tcp.middlewares.foo-ip-whitelist.ipWhiteList]
|
||||
[tcp.middlewares.foo-ip-allowlist.ipAllowList]
|
||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||
|
||||
[tcp.services]
|
||||
@ -114,12 +85,12 @@ tcp:
|
||||
router1:
|
||||
service: myService
|
||||
middlewares:
|
||||
- "foo-ip-whitelist"
|
||||
- "foo-ip-allowlist"
|
||||
rule: "Host(`example.com`)"
|
||||
|
||||
middlewares:
|
||||
foo-ip-whitelist:
|
||||
ipWhiteList:
|
||||
foo-ip-allowlist:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- "127.0.0.1/32"
|
||||
- "192.168.1.7"
|
||||
@ -137,4 +108,4 @@ tcp:
|
||||
| Middleware | Purpose | Area |
|
||||
|-------------------------------------------|---------------------------------------------------|-----------------------------|
|
||||
| [InFlightConn](inflightconn.md) | Limits the number of simultaneous connections. | Security, Request lifecycle |
|
||||
| [IPWhiteList](ipwhitelist.md) | Limit the allowed client IPs. | Security, Request lifecycle |
|
||||
| [IPAllowList](ipallowlist.md) | Limit the allowed client IPs. | Security, Request lifecycle |
|
||||
|
@ -23,7 +23,7 @@ feature by feature, of how the configuration looked like in v1, and how it now l
|
||||
- convert `acme.json` file from v1 to v2 format.
|
||||
- migrate the static configuration contained in the file `traefik.toml` to a Traefik v2 file.
|
||||
|
||||
## Frontends and Backends Are Dead... <br/>... Long Live Routers, Middlewares, and Services
|
||||
## Frontends and Backends Are Dead, Long Live Routers, Middlewares, and Services
|
||||
|
||||
During the transition from v1 to v2, a number of internal pieces and components of Traefik were rewritten and reorganized.
|
||||
As such, the combination of core notions such as frontends and backends has been replaced with the combination of [routers](../routing/routers/index.md), [services](../routing/services/index.md), and [middlewares](../middlewares/overview.md).
|
||||
@ -38,13 +38,13 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.frontend.rule=Host:test.localhost;PathPrefix:/test"
|
||||
- "traefik.frontend.auth.basic.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="K8s Ingress"
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@ -100,14 +100,14 @@ Then any router can refer to an instance of the wanted middleware.
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.routers.router0.rule=Host(`test.localhost`) && PathPrefix(`/test`)"
|
||||
- "traefik.http.routers.router0.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
|
||||
# https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
@ -278,7 +278,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
]
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
|
||||
# https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
@ -317,7 +317,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
|
||||
namespace: default
|
||||
```
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
# myTLSOptions must be defined by another provider, in this instance in the File Provider.
|
||||
# see the cross provider section
|
||||
@ -354,7 +354,7 @@ To apply a redirection:
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints=Name:web Address::80 Redirect.EntryPoint:websecure
|
||||
--entryPoints=Name:web Address::80 Redirect.EntryPoint:websecure
|
||||
--entryPoints='Name:websecure Address::443 TLS'
|
||||
```
|
||||
|
||||
@ -394,10 +394,10 @@ To apply a redirection:
|
||||
```bash tab="CLI"
|
||||
## static configuration
|
||||
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
--entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
--entrypoints.websecure.address=:443
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.redirections.entrypoint.to=websecure
|
||||
--entryPoints.web.http.redirections.entrypoint.scheme=https
|
||||
--entryPoints.websecure.address=:443
|
||||
--providers.docker=true
|
||||
```
|
||||
|
||||
@ -428,7 +428,7 @@ To apply a redirection:
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
traefik.http.routers.app.rule: Host(`example.net`)
|
||||
traefik.http.routers.app.entrypoints: web
|
||||
@ -442,7 +442,7 @@ To apply a redirection:
|
||||
traefik.http.middlewares.https_redirect.redirectscheme.permanent: true
|
||||
```
|
||||
|
||||
```yaml tab="K8s IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
@ -542,7 +542,7 @@ To apply a redirection:
|
||||
## Strip and Rewrite Path Prefixes
|
||||
|
||||
With the new core notions of v2 (introduced earlier in the section
|
||||
["Frontends and Backends Are Dead... Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)),
|
||||
["Frontends and Backends Are Dead, Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)),
|
||||
transforming the URL path prefix of incoming requests is configured with [middlewares](../middlewares/overview.md),
|
||||
after the routing step with [router rule `PathPrefix`](../routing/routers/index.md#rule).
|
||||
|
||||
@ -556,12 +556,12 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
|
||||
|
||||
!!! info "v1"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.frontend.rule=Host:example.org;PathPrefixStrip:/admin"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes Ingress"
|
||||
```yaml tab="Ingress"
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@ -588,14 +588,14 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
labels:
|
||||
- "traefik.http.routers.admin.rule=Host(`example.org`) && PathPrefix(`/admin`)"
|
||||
- "traefik.http.routers.admin.middlewares=admin-stripprefix"
|
||||
- "traefik.http.middlewares.admin-stripprefix.stripprefix.prefixes=/admin"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes IngressRoute"
|
||||
```yaml tab="IngressRoute"
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
@ -750,8 +750,8 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
--certificatesresolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.tlschallenge=true
|
||||
@ -1044,7 +1044,7 @@ To activate the dashboard, you can either:
|
||||
|
||||
!!! info "v2"
|
||||
|
||||
```yaml tab="Docker"
|
||||
```yaml tab="Docker & Swarm"
|
||||
# dynamic configuration
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=Host(`traefik.docker.localhost`)"
|
||||
@ -1078,7 +1078,7 @@ To activate the dashboard, you can either:
|
||||
routers:
|
||||
api:
|
||||
rule: Host(`traefik.docker.localhost`)
|
||||
entrypoints:
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: api@internal
|
||||
middlewares:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user