Add a new protocol
Co-authored-by: Gérald Croës <gerald@containo.us>
|
@ -58,7 +58,6 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
|
||||||
- Supports multiple load balancing algorithms
|
- 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
|
- Circuit breakers, retry
|
||||||
- High Availability with cluster mode (beta)
|
|
||||||
- See the magic through its clean web UI
|
- See the magic through its clean web UI
|
||||||
- Websocket, HTTP/2, GRPC ready
|
- Websocket, HTTP/2, GRPC ready
|
||||||
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB)
|
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB)
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
package anonymize
|
package anonymize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containous/flaeg/parse"
|
"github.com/containous/flaeg/parse"
|
||||||
"github.com/containous/traefik/acme"
|
|
||||||
"github.com/containous/traefik/config/static"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
|
"github.com/containous/traefik/provider/acme"
|
||||||
acmeprovider "github.com/containous/traefik/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/provider/file"
|
"github.com/containous/traefik/provider/file"
|
||||||
traefiktls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
|
@ -45,14 +44,6 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
IdleTimeout: parse.Duration(111 * time.Second),
|
IdleTimeout: parse.Duration(111 * time.Second),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TLS: &traefiktls.TLS{
|
|
||||||
MinVersion: "foo MinVersion",
|
|
||||||
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
|
|
||||||
ClientCA: traefiktls.ClientCA{
|
|
||||||
Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ProxyProtocol: &static.ProxyProtocol{
|
ProxyProtocol: &static.ProxyProtocol{
|
||||||
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
||||||
},
|
},
|
||||||
|
@ -66,20 +57,12 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
IdleTimeout: parse.Duration(111 * time.Second),
|
IdleTimeout: parse.Duration(111 * time.Second),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TLS: &traefiktls.TLS{
|
|
||||||
MinVersion: "fii MinVersion",
|
|
||||||
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
|
|
||||||
ClientCA: traefiktls.ClientCA{
|
|
||||||
Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ProxyProtocol: &static.ProxyProtocol{
|
ProxyProtocol: &static.ProxyProtocol{
|
||||||
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
config.ACME = &acme.ACME{
|
config.ACME = &acme.Configuration{
|
||||||
Email: "acme Email",
|
Email: "acme Email",
|
||||||
Domains: []types.Domain{
|
Domains: []types.Domain{
|
||||||
{
|
{
|
||||||
|
@ -88,16 +71,11 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Storage: "Storage",
|
Storage: "Storage",
|
||||||
OnDemand: true,
|
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
CAServer: "CAServer",
|
CAServer: "CAServer",
|
||||||
EntryPoint: "EntryPoint",
|
EntryPoint: "EntryPoint",
|
||||||
DNSChallenge: &acmeprovider.DNSChallenge{Provider: "DNSProvider"},
|
DNSChallenge: &acmeprovider.DNSChallenge{Provider: "DNSProvider"},
|
||||||
ACMELogging: true,
|
ACMELogging: true,
|
||||||
TLSConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
config.Providers = &static.Providers{
|
config.Providers = &static.Providers{
|
||||||
ProvidersThrottleDuration: parse.Duration(111 * time.Second),
|
ProvidersThrottleDuration: parse.Duration(111 * time.Second),
|
||||||
|
|
|
@ -58,7 +58,7 @@ func Test_doOnJSON(t *testing.T) {
|
||||||
"DNSProvider": "",
|
"DNSProvider": "",
|
||||||
"DelayDontCheckDNS": 0,
|
"DelayDontCheckDNS": 0,
|
||||||
"ACMELogging": false,
|
"ACMELogging": false,
|
||||||
"TLSConfig": null
|
"TLSOptions": null
|
||||||
},
|
},
|
||||||
"DefaultEntryPoints": [
|
"DefaultEntryPoints": [
|
||||||
"https",
|
"https",
|
||||||
|
@ -141,7 +141,7 @@ func Test_doOnJSON(t *testing.T) {
|
||||||
"DNSProvider": "",
|
"DNSProvider": "",
|
||||||
"DelayDontCheckDNS": 0,
|
"DelayDontCheckDNS": 0,
|
||||||
"ACMELogging": false,
|
"ACMELogging": false,
|
||||||
"TLSConfig": null
|
"TLSOptions": null
|
||||||
},
|
},
|
||||||
"DefaultEntryPoints": [
|
"DefaultEntryPoints": [
|
||||||
"https",
|
"https",
|
||||||
|
|
127
api/handler.go
|
@ -65,19 +65,20 @@ type jsonRenderer interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append add api routes on a router
|
// Append add api routes on a router
|
||||||
func (p Handler) Append(router *mux.Router) {
|
func (h Handler) Append(router *mux.Router) {
|
||||||
if p.Debug {
|
if h.Debug {
|
||||||
DebugHandler{}.Append(router)
|
DebugHandler{}.Append(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
router.Methods(http.MethodGet).Path("/api/providers").HandlerFunc(p.getProvidersHandler)
|
router.Methods(http.MethodGet).Path("/api/rawdata").HandlerFunc(h.getRawData)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}").HandlerFunc(p.getProviderHandler)
|
router.Methods(http.MethodGet).Path("/api/providers").HandlerFunc(h.getProvidersHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers").HandlerFunc(p.getRoutersHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}").HandlerFunc(h.getProviderHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers/{router}").HandlerFunc(p.getRouterHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers").HandlerFunc(h.getRoutersHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares").HandlerFunc(p.getMiddlewaresHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers/{router}").HandlerFunc(h.getRouterHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares/{middleware}").HandlerFunc(p.getMiddlewareHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares").HandlerFunc(h.getMiddlewaresHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services").HandlerFunc(p.getServicesHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares/{middleware}").HandlerFunc(h.getMiddlewareHandler)
|
||||||
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services/{service}").HandlerFunc(p.getServiceHandler)
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services").HandlerFunc(h.getServicesHandler)
|
||||||
|
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services/{service}").HandlerFunc(h.getServiceHandler)
|
||||||
|
|
||||||
// FIXME stats
|
// FIXME stats
|
||||||
// health route
|
// health route
|
||||||
|
@ -85,15 +86,30 @@ func (p Handler) Append(router *mux.Router) {
|
||||||
|
|
||||||
version.Handler{}.Append(router)
|
version.Handler{}.Append(router)
|
||||||
|
|
||||||
if p.Dashboard {
|
if h.Dashboard {
|
||||||
DashboardHandler{Assets: p.DashboardAssets}.Append(router)
|
DashboardHandler{Assets: h.DashboardAssets}.Append(router)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getProvidersHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRawData(rw http.ResponseWriter, request *http.Request) {
|
||||||
|
if h.CurrentConfigurations != nil {
|
||||||
|
currentConfigurations, ok := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
if !ok {
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := templateRenderer.JSON(rw, http.StatusOK, currentConfigurations)
|
||||||
|
if err != nil {
|
||||||
|
log.FromContext(request.Context()).Error(err)
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handler) getProvidersHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
// FIXME handle currentConfiguration
|
// FIXME handle currentConfiguration
|
||||||
if p.CurrentConfigurations != nil {
|
if h.CurrentConfigurations != nil {
|
||||||
currentConfigurations, ok := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations, ok := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
if !ok {
|
if !ok {
|
||||||
rw.WriteHeader(http.StatusOK)
|
rw.WriteHeader(http.StatusOK)
|
||||||
return
|
return
|
||||||
|
@ -115,10 +131,10 @@ func (p Handler) getProvidersHandler(rw http.ResponseWriter, request *http.Reque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getProviderHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -126,8 +142,13 @@ func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var routers []ResourceIdentifier
|
var routers []ResourceIdentifier
|
||||||
for name := range provider.Routers {
|
for name := range provider.HTTP.Routers {
|
||||||
routers = append(routers, ResourceIdentifier{
|
routers = append(routers, ResourceIdentifier{
|
||||||
ID: name,
|
ID: name,
|
||||||
Path: "/api/providers/" + providerID + "/routers",
|
Path: "/api/providers/" + providerID + "/routers",
|
||||||
|
@ -135,7 +156,7 @@ func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
}
|
}
|
||||||
|
|
||||||
var services []ResourceIdentifier
|
var services []ResourceIdentifier
|
||||||
for name := range provider.Services {
|
for name := range provider.HTTP.Services {
|
||||||
services = append(services, ResourceIdentifier{
|
services = append(services, ResourceIdentifier{
|
||||||
ID: name,
|
ID: name,
|
||||||
Path: "/api/providers/" + providerID + "/services",
|
Path: "/api/providers/" + providerID + "/services",
|
||||||
|
@ -143,7 +164,7 @@ func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
}
|
}
|
||||||
|
|
||||||
var middlewares []ResourceIdentifier
|
var middlewares []ResourceIdentifier
|
||||||
for name := range provider.Middlewares {
|
for name := range provider.HTTP.Middlewares {
|
||||||
middlewares = append(middlewares, ResourceIdentifier{
|
middlewares = append(middlewares, ResourceIdentifier{
|
||||||
ID: name,
|
ID: name,
|
||||||
Path: "/api/providers/" + providerID + "/middlewares",
|
Path: "/api/providers/" + providerID + "/middlewares",
|
||||||
|
@ -159,10 +180,10 @@ func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getRoutersHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRoutersHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -170,8 +191,13 @@ func (p Handler) getRoutersHandler(rw http.ResponseWriter, request *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var routers []RouterRepresentation
|
var routers []RouterRepresentation
|
||||||
for name, router := range provider.Routers {
|
for name, router := range provider.HTTP.Routers {
|
||||||
routers = append(routers, RouterRepresentation{Router: router, ID: name})
|
routers = append(routers, RouterRepresentation{Router: router, ID: name})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,11 +208,11 @@ func (p Handler) getRoutersHandler(rw http.ResponseWriter, request *http.Request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getRouterHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getRouterHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
routerID := mux.Vars(request)["router"]
|
routerID := mux.Vars(request)["router"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -194,7 +220,12 @@ func (p Handler) getRouterHandler(rw http.ResponseWriter, request *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
router, ok := provider.Routers[routerID]
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
router, ok := provider.HTTP.Routers[routerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
http.NotFound(rw, request)
|
||||||
return
|
return
|
||||||
|
@ -207,10 +238,10 @@ func (p Handler) getRouterHandler(rw http.ResponseWriter, request *http.Request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getMiddlewaresHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getMiddlewaresHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -218,8 +249,13 @@ func (p Handler) getMiddlewaresHandler(rw http.ResponseWriter, request *http.Req
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var middlewares []MiddlewareRepresentation
|
var middlewares []MiddlewareRepresentation
|
||||||
for name, middleware := range provider.Middlewares {
|
for name, middleware := range provider.HTTP.Middlewares {
|
||||||
middlewares = append(middlewares, MiddlewareRepresentation{Middleware: middleware, ID: name})
|
middlewares = append(middlewares, MiddlewareRepresentation{Middleware: middleware, ID: name})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,11 +266,11 @@ func (p Handler) getMiddlewaresHandler(rw http.ResponseWriter, request *http.Req
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getMiddlewareHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getMiddlewareHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
middlewareID := mux.Vars(request)["middleware"]
|
middlewareID := mux.Vars(request)["middleware"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -242,7 +278,12 @@ func (p Handler) getMiddlewareHandler(rw http.ResponseWriter, request *http.Requ
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware, ok := provider.Middlewares[middlewareID]
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
middleware, ok := provider.HTTP.Middlewares[middlewareID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
http.NotFound(rw, request)
|
||||||
return
|
return
|
||||||
|
@ -255,10 +296,10 @@ func (p Handler) getMiddlewareHandler(rw http.ResponseWriter, request *http.Requ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getServicesHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getServicesHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -266,8 +307,13 @@ func (p Handler) getServicesHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var services []ServiceRepresentation
|
var services []ServiceRepresentation
|
||||||
for name, service := range provider.Services {
|
for name, service := range provider.HTTP.Services {
|
||||||
services = append(services, ServiceRepresentation{Service: service, ID: name})
|
services = append(services, ServiceRepresentation{Service: service, ID: name})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,11 +324,11 @@ func (p Handler) getServicesHandler(rw http.ResponseWriter, request *http.Reques
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Handler) getServiceHandler(rw http.ResponseWriter, request *http.Request) {
|
func (h Handler) getServiceHandler(rw http.ResponseWriter, request *http.Request) {
|
||||||
providerID := mux.Vars(request)["provider"]
|
providerID := mux.Vars(request)["provider"]
|
||||||
serviceID := mux.Vars(request)["service"]
|
serviceID := mux.Vars(request)["service"]
|
||||||
|
|
||||||
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
|
currentConfigurations := h.CurrentConfigurations.Get().(config.Configurations)
|
||||||
|
|
||||||
provider, ok := currentConfigurations[providerID]
|
provider, ok := currentConfigurations[providerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -290,7 +336,12 @@ func (p Handler) getServiceHandler(rw http.ResponseWriter, request *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
service, ok := provider.Services[serviceID]
|
if provider.HTTP == nil {
|
||||||
|
http.NotFound(rw, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service, ok := provider.HTTP.Services[serviceID]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(rw, request)
|
http.NotFound(rw, request)
|
||||||
return
|
return
|
||||||
|
|
|
@ -30,8 +30,10 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers",
|
path: "/api/providers",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Routers: map[string]*config.Router{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {EntryPoints: []string{"foo", "bar"}},
|
Routers: map[string]*config.Router{
|
||||||
|
"bar": {EntryPoints: []string{"foo", "bar"}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -42,18 +44,20 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo",
|
path: "/api/providers/foo",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Routers: map[string]*config.Router{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {EntryPoints: []string{"foo", "bar"}},
|
Routers: map[string]*config.Router{
|
||||||
},
|
"bar": {EntryPoints: []string{"foo", "bar"}},
|
||||||
Middlewares: map[string]*config.Middleware{
|
|
||||||
"bar": {
|
|
||||||
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
|
||||||
},
|
},
|
||||||
},
|
Middlewares: map[string]*config.Middleware{
|
||||||
Services: map[string]*config.Service{
|
"bar": {
|
||||||
"foo": {
|
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
||||||
LoadBalancer: &config.LoadBalancerService{
|
},
|
||||||
Method: "wrr",
|
},
|
||||||
|
Services: map[string]*config.Service{
|
||||||
|
"foo": {
|
||||||
|
LoadBalancer: &config.LoadBalancerService{
|
||||||
|
Method: "wrr",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -72,8 +76,10 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/routers",
|
path: "/api/providers/foo/routers",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Routers: map[string]*config.Router{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {EntryPoints: []string{"foo", "bar"}},
|
Routers: map[string]*config.Router{
|
||||||
|
"bar": {EntryPoints: []string{"foo", "bar"}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -84,8 +90,10 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/routers/bar",
|
path: "/api/providers/foo/routers/bar",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Routers: map[string]*config.Router{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {EntryPoints: []string{"foo", "bar"}},
|
Routers: map[string]*config.Router{
|
||||||
|
"bar": {EntryPoints: []string{"foo", "bar"}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -104,10 +112,12 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/services",
|
path: "/api/providers/foo/services",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Services: map[string]*config.Service{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"foo": {
|
Services: map[string]*config.Service{
|
||||||
LoadBalancer: &config.LoadBalancerService{
|
"foo": {
|
||||||
Method: "wrr",
|
LoadBalancer: &config.LoadBalancerService{
|
||||||
|
Method: "wrr",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -120,10 +130,12 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/services/foo",
|
path: "/api/providers/foo/services/foo",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Services: map[string]*config.Service{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"foo": {
|
Services: map[string]*config.Service{
|
||||||
LoadBalancer: &config.LoadBalancerService{
|
"foo": {
|
||||||
Method: "wrr",
|
LoadBalancer: &config.LoadBalancerService{
|
||||||
|
Method: "wrr",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -144,9 +156,11 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/middlewares",
|
path: "/api/providers/foo/middlewares",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Middlewares: map[string]*config.Middleware{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {
|
Middlewares: map[string]*config.Middleware{
|
||||||
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
"bar": {
|
||||||
|
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -158,9 +172,11 @@ func TestHandler_Configuration(t *testing.T) {
|
||||||
path: "/api/providers/foo/middlewares/bar",
|
path: "/api/providers/foo/middlewares/bar",
|
||||||
configuration: config.Configurations{
|
configuration: config.Configurations{
|
||||||
"foo": {
|
"foo": {
|
||||||
Middlewares: map[string]*config.Middleware{
|
HTTP: &config.HTTPConfiguration{
|
||||||
"bar": {
|
Middlewares: map[string]*config.Middleware{
|
||||||
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
"bar": {
|
||||||
|
AddPrefix: &config.AddPrefix{Prefix: "bar"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,7 +45,7 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newConfig := config.Configuration{
|
newConfig := config.HTTPConfiguration{
|
||||||
Routers: make(map[string]*config.Router),
|
Routers: make(map[string]*config.Router),
|
||||||
Middlewares: make(map[string]*config.Middleware),
|
Middlewares: make(map[string]*config.Middleware),
|
||||||
Services: make(map[string]*config.Service),
|
Services: make(map[string]*config.Service),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package healthcheck
|
package healthcheck
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -59,13 +58,14 @@ func Do(staticConfiguration static.Configuration) (*http.Response, error) {
|
||||||
client := &http.Client{Timeout: 5 * time.Second}
|
client := &http.Client{Timeout: 5 * time.Second}
|
||||||
protocol := "http"
|
protocol := "http"
|
||||||
|
|
||||||
if pingEntryPoint.TLS != nil {
|
// FIXME Handle TLS on ping etc...
|
||||||
protocol = "https"
|
// if pingEntryPoint.TLS != nil {
|
||||||
tr := &http.Transport{
|
// protocol = "https"
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
// tr := &http.Transport{
|
||||||
}
|
// TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
client.Transport = tr
|
// }
|
||||||
}
|
// client.Transport = tr
|
||||||
|
// }
|
||||||
|
|
||||||
path := "/"
|
path := "/"
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ import (
|
||||||
"github.com/abronan/valkeyrie/store"
|
"github.com/abronan/valkeyrie/store"
|
||||||
"github.com/containous/flaeg"
|
"github.com/containous/flaeg"
|
||||||
"github.com/containous/staert"
|
"github.com/containous/staert"
|
||||||
"github.com/containous/traefik/acme"
|
|
||||||
"github.com/containous/traefik/cluster"
|
|
||||||
"github.com/containous/traefik/cmd"
|
"github.com/containous/traefik/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,7 +15,7 @@ import (
|
||||||
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
|
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
|
||||||
return &flaeg.Command{
|
return &flaeg.Command{
|
||||||
Name: "storeconfig",
|
Name: "storeconfig",
|
||||||
Description: `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
|
Description: `Stores the static traefik configuration into a Key-value stores. Traefik will not start.`,
|
||||||
Config: traefikConfiguration,
|
Config: traefikConfiguration,
|
||||||
DefaultPointersConfig: traefikPointersConfiguration,
|
DefaultPointersConfig: traefikPointersConfiguration,
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]string{
|
||||||
|
@ -71,48 +69,48 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if traefikConfiguration.Configuration.ACME != nil {
|
// if traefikConfiguration.Configuration.ACME != nil {
|
||||||
account := &acme.Account{}
|
// account := &acme.Account{}
|
||||||
|
//
|
||||||
accountInitialized, err := keyExists(kv, traefikConfiguration.Configuration.ACME.Storage)
|
// accountInitialized, err := keyExists(kv, traefikConfiguration.Configuration.ACME.Storage)
|
||||||
if err != nil && err != store.ErrKeyNotFound {
|
// if err != nil && err != store.ErrKeyNotFound {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Check to see if ACME account object is already in kv store
|
// // Check to see if ACME account object is already in kv store
|
||||||
if traefikConfiguration.Configuration.ACME.OverrideCertificates || !accountInitialized {
|
// if traefikConfiguration.Configuration.ACME.OverrideCertificates || !accountInitialized {
|
||||||
|
//
|
||||||
// Store the ACME Account into the KV Store
|
// // Stores the ACME Account into the KV Store
|
||||||
// Certificates in KV Store will be overridden
|
// // Certificates in KV Stores will be overridden
|
||||||
meta := cluster.NewMetadata(account)
|
// meta := cluster.NewMetadata(account)
|
||||||
err = meta.Marshall()
|
// err = meta.Marshall()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
source := staert.KvSource{
|
// source := staert.KvSource{
|
||||||
Store: kv,
|
// Store: kv,
|
||||||
Prefix: traefikConfiguration.Configuration.ACME.Storage,
|
// Prefix: traefikConfiguration.Configuration.ACME.Storage,
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
err = source.StoreConfig(meta)
|
// err = source.StoreConfig(meta)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyExists(source *staert.KvSource, key string) (bool, error) {
|
// func keyExists(source *staert.KvSource, key string) (bool, error) {
|
||||||
list, err := source.List(key, nil)
|
// list, err := source.List(key, nil)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return false, err
|
// return false, err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return len(list) > 0, nil
|
// return len(list) > 0, nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
// CreateKvSource creates KvSource
|
// CreateKvSource creates KvSource
|
||||||
// TLS support is enable for Consul and Etcd backends
|
// TLS support is enable for Consul and Etcd backends
|
||||||
|
|
|
@ -245,36 +245,29 @@ func runCmd(staticConfiguration *static.Configuration, configFile string) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverEntryPoints := make(server.EntryPoints)
|
serverEntryPointsTCP := make(server.TCPEntryPoints)
|
||||||
for entryPointName, config := range staticConfiguration.EntryPoints {
|
for entryPointName, config := range staticConfiguration.EntryPoints {
|
||||||
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
|
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
|
||||||
logger := log.FromContext(ctx)
|
serverEntryPointsTCP[entryPointName], err = server.NewTCPEntryPoint(ctx, config)
|
||||||
|
|
||||||
serverEntryPoint, err := server.NewEntryPoint(ctx, config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while building entryPoint %s: %v", entryPointName, err)
|
return fmt.Errorf("error while building entryPoint %s: %v", entryPointName, err)
|
||||||
}
|
}
|
||||||
|
serverEntryPointsTCP[entryPointName].RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProvider)
|
||||||
|
|
||||||
serverEntryPoint.RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProvider)
|
|
||||||
|
|
||||||
if acmeProvider != nil && entryPointName == acmeProvider.EntryPoint {
|
|
||||||
logger.Debugf("Setting Acme Certificate store from Entrypoint")
|
|
||||||
acmeProvider.SetCertificateStore(serverEntryPoint.Certs)
|
|
||||||
|
|
||||||
if acmeProvider.OnDemand {
|
|
||||||
serverEntryPoint.OnDemandListener = acmeProvider.ListenRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// TLS ALPN 01
|
|
||||||
if acmeProvider.TLSChallenge != nil && acmeProvider.HTTPChallenge == nil && acmeProvider.DNSChallenge == nil {
|
|
||||||
serverEntryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
serverEntryPoints[entryPointName] = serverEntryPoint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPoints)
|
tlsManager := traefiktls.NewManager()
|
||||||
|
|
||||||
|
if acmeProvider != nil {
|
||||||
|
acmeProvider.SetTLSManager(tlsManager)
|
||||||
|
if acmeProvider.TLSChallenge != nil &&
|
||||||
|
acmeProvider.HTTPChallenge == nil &&
|
||||||
|
acmeProvider.DNSChallenge == nil {
|
||||||
|
tlsManager.TLSAlpnGetter = acmeProvider.GetTLSALPNCertificate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPointsTCP, tlsManager)
|
||||||
|
|
||||||
if acmeProvider != nil && acmeProvider.OnHostRule {
|
if acmeProvider != nil && acmeProvider.OnHostRule {
|
||||||
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
|
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
|
||||||
|
|
|
@ -13,11 +13,28 @@ import (
|
||||||
|
|
||||||
// Router holds the router configuration.
|
// Router holds the router configuration.
|
||||||
type Router struct {
|
type Router struct {
|
||||||
EntryPoints []string `json:"entryPoints"`
|
EntryPoints []string `json:"entryPoints"`
|
||||||
Middlewares []string `json:"middlewares,omitempty" toml:",omitempty"`
|
Middlewares []string `json:"middlewares,omitempty" toml:",omitempty"`
|
||||||
Service string `json:"service,omitempty" toml:",omitempty"`
|
Service string `json:"service,omitempty" toml:",omitempty"`
|
||||||
Rule string `json:"rule,omitempty" toml:",omitempty"`
|
Rule string `json:"rule,omitempty" toml:",omitempty"`
|
||||||
Priority int `json:"priority,omitempty" toml:"priority,omitzero"`
|
Priority int `json:"priority,omitempty" toml:"priority,omitzero"`
|
||||||
|
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitzero" label:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterTLSConfig holds the TLS configuration for a router
|
||||||
|
type RouterTLSConfig struct{}
|
||||||
|
|
||||||
|
// TCPRouter holds the router configuration.
|
||||||
|
type TCPRouter struct {
|
||||||
|
EntryPoints []string `json:"entryPoints"`
|
||||||
|
Service string `json:"service,omitempty" toml:",omitempty"`
|
||||||
|
Rule string `json:"rule,omitempty" toml:",omitempty"`
|
||||||
|
TLS *RouterTCPTLSConfig `json:"tls,omitempty" toml:"tls,omitzero" label:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterTCPTLSConfig holds the TLS configuration for a router
|
||||||
|
type RouterTCPTLSConfig struct {
|
||||||
|
Passthrough bool `json:"passthrough,omitempty" toml:"passthrough,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadBalancerService holds the LoadBalancerService configuration.
|
// LoadBalancerService holds the LoadBalancerService configuration.
|
||||||
|
@ -30,6 +47,12 @@ type LoadBalancerService struct {
|
||||||
ResponseForwarding *ResponseForwarding `json:"forwardingResponse,omitempty" toml:",omitempty"`
|
ResponseForwarding *ResponseForwarding `json:"forwardingResponse,omitempty" toml:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPLoadBalancerService holds the LoadBalancerService configuration.
|
||||||
|
type TCPLoadBalancerService struct {
|
||||||
|
Servers []TCPServer `json:"servers,omitempty" toml:",omitempty" label-slice-as-struct:"server"`
|
||||||
|
Method string `json:"method,omitempty" toml:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Mergeable tells if the given service is mergeable.
|
// Mergeable tells if the given service is mergeable.
|
||||||
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
||||||
savedServers := l.Servers
|
savedServers := l.Servers
|
||||||
|
@ -71,6 +94,12 @@ type Server struct {
|
||||||
Weight int `json:"weight"`
|
Weight int `json:"weight"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPServer holds a TCP Server configuration
|
||||||
|
type TCPServer struct {
|
||||||
|
Address string `json:"address" label:"-"`
|
||||||
|
Weight int `json:"weight"`
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults Default values for a Server.
|
// SetDefaults Default values for a Server.
|
||||||
func (s *Server) SetDefaults() {
|
func (s *Server) SetDefaults() {
|
||||||
s.Weight = 1
|
s.Weight = 1
|
||||||
|
@ -175,18 +204,37 @@ type Message struct {
|
||||||
Configuration *Configuration
|
Configuration *Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration is the root of the dynamic configuration
|
||||||
|
type Configuration struct {
|
||||||
|
HTTP *HTTPConfiguration
|
||||||
|
TCP *TCPConfiguration
|
||||||
|
TLS []*traefiktls.Configuration `json:"-" label:"-"`
|
||||||
|
TLSOptions map[string]traefiktls.TLS
|
||||||
|
TLSStores map[string]traefiktls.Store
|
||||||
|
}
|
||||||
|
|
||||||
// Configurations is for currentConfigurations Map.
|
// Configurations is for currentConfigurations Map.
|
||||||
type Configurations map[string]*Configuration
|
type Configurations map[string]*Configuration
|
||||||
|
|
||||||
// Configuration FIXME better name?
|
// HTTPConfiguration FIXME better name?
|
||||||
type Configuration struct {
|
type HTTPConfiguration struct {
|
||||||
Routers map[string]*Router `json:"routers,omitempty" toml:",omitempty"`
|
Routers map[string]*Router `json:"routers,omitempty" toml:",omitempty"`
|
||||||
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:",omitempty"`
|
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:",omitempty"`
|
||||||
Services map[string]*Service `json:"services,omitempty" toml:",omitempty"`
|
Services map[string]*Service `json:"services,omitempty" toml:",omitempty"`
|
||||||
TLS []*traefiktls.Configuration `json:"-" label:"-"`
|
}
|
||||||
|
|
||||||
|
// TCPConfiguration FIXME better name?
|
||||||
|
type TCPConfiguration struct {
|
||||||
|
Routers map[string]*TCPRouter `json:"routers,omitempty" toml:",omitempty"`
|
||||||
|
Services map[string]*TCPService `json:"services,omitempty" toml:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service holds a service configuration (can only be of one type at the same time).
|
// Service holds a service configuration (can only be of one type at the same time).
|
||||||
type Service struct {
|
type Service struct {
|
||||||
LoadBalancer *LoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
|
LoadBalancer *LoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPService holds a tcp service configuration (can only be of one type at the same time).
|
||||||
|
type TCPService struct {
|
||||||
|
LoadBalancer *TCPLoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
|
||||||
|
}
|
||||||
|
|
|
@ -5,14 +5,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/tls"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// EntryPoint holds the entry point configuration.
|
// EntryPoint holds the entry point configuration.
|
||||||
type EntryPoint struct {
|
type EntryPoint struct {
|
||||||
Address string
|
Address string
|
||||||
Transport *EntryPointsTransport
|
Transport *EntryPointsTransport
|
||||||
TLS *tls.TLS
|
|
||||||
ProxyProtocol *ProxyProtocol
|
ProxyProtocol *ProxyProtocol
|
||||||
ForwardedHeaders *ForwardedHeaders
|
ForwardedHeaders *ForwardedHeaders
|
||||||
}
|
}
|
||||||
|
@ -65,14 +63,8 @@ func (ep *EntryPoints) Type() string {
|
||||||
func (ep *EntryPoints) Set(value string) error {
|
func (ep *EntryPoints) Set(value string) error {
|
||||||
result := parseEntryPointsConfiguration(value)
|
result := parseEntryPointsConfiguration(value)
|
||||||
|
|
||||||
configTLS, err := makeEntryPointTLS(result)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
(*ep)[result["name"]] = &EntryPoint{
|
(*ep)[result["name"]] = &EntryPoint{
|
||||||
Address: result["address"],
|
Address: result["address"],
|
||||||
TLS: configTLS,
|
|
||||||
ProxyProtocol: makeEntryPointProxyProtocol(result),
|
ProxyProtocol: makeEntryPointProxyProtocol(result),
|
||||||
ForwardedHeaders: makeEntryPointForwardedHeaders(result),
|
ForwardedHeaders: makeEntryPointForwardedHeaders(result),
|
||||||
}
|
}
|
||||||
|
@ -100,55 +92,6 @@ func makeEntryPointProxyProtocol(result map[string]string) *ProxyProtocol {
|
||||||
return proxyProtocol
|
return proxyProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) {
|
|
||||||
var configTLS *tls.TLS
|
|
||||||
|
|
||||||
if len(result["tls"]) > 0 {
|
|
||||||
certs := tls.Certificates{}
|
|
||||||
if err := certs.Set(result["tls"]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
configTLS = &tls.TLS{}
|
|
||||||
} else if len(result["tls_acme"]) > 0 {
|
|
||||||
configTLS = &tls.TLS{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if configTLS != nil {
|
|
||||||
if len(result["ca"]) > 0 {
|
|
||||||
files := tls.FilesOrContents{}
|
|
||||||
if err := files.Set(result["ca"]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
optional := toBool(result, "ca_optional")
|
|
||||||
configTLS.ClientCA = tls.ClientCA{
|
|
||||||
Files: files,
|
|
||||||
Optional: optional,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result["tls_minversion"]) > 0 {
|
|
||||||
configTLS.MinVersion = result["tls_minversion"]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result["tls_ciphersuites"]) > 0 {
|
|
||||||
configTLS.CipherSuites = strings.Split(result["tls_ciphersuites"], ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result["tls_snistrict"]) > 0 {
|
|
||||||
configTLS.SniStrict = toBool(result, "tls_snistrict")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result["tls_defaultcertificate_cert"]) > 0 && len(result["tls_defaultcertificate_key"]) > 0 {
|
|
||||||
configTLS.DefaultCertificate = &tls.Certificate{
|
|
||||||
CertFile: tls.FileOrContent(result["tls_defaultcertificate_cert"]),
|
|
||||||
KeyFile: tls.FileOrContent(result["tls_defaultcertificate_key"]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configTLS, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseEntryPointsConfiguration(raw string) map[string]string {
|
func parseEntryPointsConfiguration(raw string) map[string]string {
|
||||||
sections := strings.Fields(raw)
|
sections := strings.Fields(raw)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package static
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/tls"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -18,10 +17,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
||||||
name: "all parameters",
|
name: "all parameters",
|
||||||
value: "Name:foo " +
|
value: "Name:foo " +
|
||||||
"Address::8000 " +
|
"Address::8000 " +
|
||||||
"TLS:goo,gii " +
|
|
||||||
"TLS " +
|
|
||||||
"TLS.MinVersion:VersionTLS11 " +
|
|
||||||
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
|
||||||
"CA:car " +
|
"CA:car " +
|
||||||
"CA.Optional:true " +
|
"CA.Optional:true " +
|
||||||
"Redirect.EntryPoint:https " +
|
"Redirect.EntryPoint:https " +
|
||||||
|
@ -76,10 +71,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
||||||
"redirect_permanent": "true",
|
"redirect_permanent": "true",
|
||||||
"redirect_regex": "http://localhost/(.*)",
|
"redirect_regex": "http://localhost/(.*)",
|
||||||
"redirect_replacement": "http://mydomain/$1",
|
"redirect_replacement": "http://mydomain/$1",
|
||||||
"tls": "goo,gii",
|
|
||||||
"tls_acme": "TLS",
|
|
||||||
"tls_ciphersuites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
|
||||||
"tls_minversion": "VersionTLS11",
|
|
||||||
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
|
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
|
||||||
"whitelist_ipstrategy_depth": "3",
|
"whitelist_ipstrategy_depth": "3",
|
||||||
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
|
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
|
||||||
|
@ -95,15 +86,6 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
||||||
"compress": "on",
|
"compress": "on",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "TLS",
|
|
||||||
value: "Name:foo TLS:goo TLS",
|
|
||||||
expectedResult: map[string]string{
|
|
||||||
"name": "foo",
|
|
||||||
"tls": "goo",
|
|
||||||
"tls_acme": "TLS",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
@ -185,23 +167,12 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
name: "all parameters camelcase",
|
name: "all parameters camelcase",
|
||||||
expression: "Name:foo " +
|
expression: "Name:foo " +
|
||||||
"Address::8000 " +
|
"Address::8000 " +
|
||||||
"TLS " +
|
|
||||||
"TLS.MinVersion:VersionTLS11 " +
|
|
||||||
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
|
||||||
"CA:car " +
|
"CA:car " +
|
||||||
"CA.Optional:true " +
|
"CA.Optional:true " +
|
||||||
"ProxyProtocol.TrustedIPs:192.168.0.1 ",
|
"ProxyProtocol.TrustedIPs:192.168.0.1 ",
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
TLS: &tls.TLS{
|
|
||||||
MinVersion: "VersionTLS11",
|
|
||||||
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
|
||||||
ClientCA: tls.ClientCA{
|
|
||||||
Files: tls.FilesOrContents{"car"},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ProxyProtocol: &ProxyProtocol{
|
ProxyProtocol: &ProxyProtocol{
|
||||||
Insecure: false,
|
Insecure: false,
|
||||||
TrustedIPs: []string{"192.168.0.1"},
|
TrustedIPs: []string{"192.168.0.1"},
|
||||||
|
@ -223,14 +194,6 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
TLS: &tls.TLS{
|
|
||||||
MinVersion: "VersionTLS11",
|
|
||||||
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
|
||||||
ClientCA: tls.ClientCA{
|
|
||||||
Files: tls.FilesOrContents{"car"},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ProxyProtocol: &ProxyProtocol{
|
ProxyProtocol: &ProxyProtocol{
|
||||||
Insecure: false,
|
Insecure: false,
|
||||||
TrustedIPs: []string{"192.168.0.1"},
|
TrustedIPs: []string{"192.168.0.1"},
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containous/flaeg/parse"
|
"github.com/containous/flaeg/parse"
|
||||||
"github.com/containous/traefik/acme"
|
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/old/provider/boltdb"
|
"github.com/containous/traefik/old/provider/boltdb"
|
||||||
"github.com/containous/traefik/old/provider/consul"
|
"github.com/containous/traefik/old/provider/consul"
|
||||||
|
@ -70,7 +69,7 @@ type Configuration struct {
|
||||||
|
|
||||||
HostResolver *types.HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
|
HostResolver *types.HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
|
||||||
|
|
||||||
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
|
ACME *acmeprovider.Configuration `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global holds the global configuration.
|
// Global holds the global configuration.
|
||||||
|
@ -338,10 +337,6 @@ func (c *Configuration) initACMEProvider() {
|
||||||
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
|
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
|
||||||
c.ACME.HTTPChallenge = nil
|
c.ACME.HTTPChallenge = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ACME.OnDemand {
|
|
||||||
log.Warn("ACME.OnDemand is deprecated")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,18 +344,11 @@ func (c *Configuration) initACMEProvider() {
|
||||||
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
|
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
|
||||||
if c.ACME != nil {
|
if c.ACME != nil {
|
||||||
if len(c.ACME.Storage) == 0 {
|
if len(c.ACME.Storage) == 0 {
|
||||||
// Delete the ACME configuration to avoid starting ACME in cluster mode
|
|
||||||
c.ACME = nil
|
|
||||||
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
|
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
|
||||||
}
|
}
|
||||||
provider := &acmeprovider.Provider{}
|
return &acmeprovider.Provider{
|
||||||
provider.Configuration = convertACMEChallenge(c.ACME)
|
Configuration: c.ACME,
|
||||||
|
}, nil
|
||||||
store := acmeprovider.NewLocalStore(provider.Storage)
|
|
||||||
provider.Store = store
|
|
||||||
acme.ConvertToNewFormat(provider.Storage)
|
|
||||||
c.ACME = nil
|
|
||||||
return provider, nil
|
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -368,12 +356,26 @@ func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
|
||||||
// ValidateConfiguration validate that configuration is coherent
|
// ValidateConfiguration validate that configuration is coherent
|
||||||
func (c *Configuration) ValidateConfiguration() {
|
func (c *Configuration) ValidateConfiguration() {
|
||||||
if c.ACME != nil {
|
if c.ACME != nil {
|
||||||
if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
|
for _, domain := range c.ACME.Domains {
|
||||||
log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
|
if domain.Main != dns01.UnFqdn(domain.Main) {
|
||||||
} else if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
|
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
|
||||||
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
|
}
|
||||||
|
for _, san := range domain.SANs {
|
||||||
|
if san != dns01.UnFqdn(san) {
|
||||||
|
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME Validate store config?
|
||||||
|
// if c.ACME != nil {
|
||||||
|
// if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
|
||||||
|
// log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
|
||||||
|
// }
|
||||||
|
// else if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
|
||||||
|
// log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSafeACMECAServer(caServerSrc string) string {
|
func getSafeACMECAServer(caServerSrc string) string {
|
||||||
|
@ -395,47 +397,3 @@ func getSafeACMECAServer(caServerSrc string) string {
|
||||||
|
|
||||||
return caServerSrc
|
return caServerSrc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
func convertACMEChallenge(oldACMEChallenge *acme.ACME) *acmeprovider.Configuration {
|
|
||||||
conf := &acmeprovider.Configuration{
|
|
||||||
KeyType: oldACMEChallenge.KeyType,
|
|
||||||
OnHostRule: oldACMEChallenge.OnHostRule,
|
|
||||||
OnDemand: oldACMEChallenge.OnDemand,
|
|
||||||
Email: oldACMEChallenge.Email,
|
|
||||||
Storage: oldACMEChallenge.Storage,
|
|
||||||
ACMELogging: oldACMEChallenge.ACMELogging,
|
|
||||||
CAServer: oldACMEChallenge.CAServer,
|
|
||||||
EntryPoint: oldACMEChallenge.EntryPoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, domain := range oldACMEChallenge.Domains {
|
|
||||||
if domain.Main != dns01.UnFqdn(domain.Main) {
|
|
||||||
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
|
|
||||||
}
|
|
||||||
for _, san := range domain.SANs {
|
|
||||||
if san != dns01.UnFqdn(san) {
|
|
||||||
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conf.Domains = append(conf.Domains, domain)
|
|
||||||
}
|
|
||||||
if oldACMEChallenge.HTTPChallenge != nil {
|
|
||||||
conf.HTTPChallenge = &acmeprovider.HTTPChallenge{
|
|
||||||
EntryPoint: oldACMEChallenge.HTTPChallenge.EntryPoint,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldACMEChallenge.DNSChallenge != nil {
|
|
||||||
conf.DNSChallenge = &acmeprovider.DNSChallenge{
|
|
||||||
Provider: oldACMEChallenge.DNSChallenge.Provider,
|
|
||||||
DelayBeforeCheck: oldACMEChallenge.DNSChallenge.DelayBeforeCheck,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldACMEChallenge.TLSChallenge != nil {
|
|
||||||
conf.TLSChallenge = &acmeprovider.TLSChallenge{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conf
|
|
||||||
}
|
|
||||||
|
|
Before Width: | Height: | Size: 458 KiB After Width: | Height: | Size: 361 KiB |
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 376 KiB |
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 377 KiB |
Before Width: | Height: | Size: 386 KiB After Width: | Height: | Size: 378 KiB |
|
@ -48,8 +48,8 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col
|
||||||
??? example "Original configuration"
|
??? example "Original configuration"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -78,8 +78,8 @@ Once a day (the first call begins 10 minutes after the start of Traefik), we col
|
||||||
??? example "Resulting Obfuscated Configuration"
|
??? example "Resulting Obfuscated Configuration"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
|
@ -24,11 +24,11 @@ You no longer need to create and synchronize configuration files cluttered with
|
||||||
|
|
||||||
!!! note "Many different rules"
|
!!! note "Many different rules"
|
||||||
|
|
||||||
In the example above, we used the request [path](../routing/routers.md#rule) to determine which service was in charge, but of course you can use many other different [rules](../routing/routers.md#rule).
|
In the example above, we used the request [path](../routing/routers/index.md#rule) to determine which service was in charge, but of course you can use many other different [rules](../routing/routers/index.md#rule).
|
||||||
|
|
||||||
!!! note "Updating the requests"
|
!!! note "Updating the requests"
|
||||||
|
|
||||||
In the [middleware](../middlewares/overview.md) section, you can learn about how to update the requests before forwarding them to the services.
|
In the [middleware](../middlewares/overview.md) section, you can learn about how to update the requests before forwarding them to the services.
|
||||||
|
|
||||||
!!! question "How does Traefik discover the services?"
|
!!! question "How does Traefik discover the services?"
|
||||||
|
|
||||||
|
|
|
@ -3,56 +3,52 @@
|
||||||
Automatic HTTPS
|
Automatic HTTPS
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
|
||||||
Traefik can automatically generate certificates for your domains using an ACME provider (like Let's Encrypt).
|
You can configure Traefik to use an ACME provider (like Let's Encrypt) for automatic certificate generation.
|
||||||
|
|
||||||
!!! warning "Let's Encrypt and Rate Limiting"
|
!!! warning "Let's Encrypt and Rate Limiting"
|
||||||
Note that Let's Encrypt has [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Configuring ACME on the Https EntryPoint"
|
??? example "Enabling ACME"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.web]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.http-tls]
|
[entrypoints.http-tls]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
[entryPoints.http-tls.tls] # enabling TLS
|
|
||||||
|
[acme] # every router with TLS enabled will now be able to use ACME for its certificates
|
||||||
[acme]
|
|
||||||
email = "your-email@your-domain.org"
|
email = "your-email@your-domain.org"
|
||||||
storage = "acme.json"
|
storage = "acme.json"
|
||||||
entryPoint = "http-tls" # acme is enabled on http-tls
|
onHostRule = true # dynamic generation based on the Host() & HostSNI() matchers
|
||||||
onHostRule = true # dynamic generation based on the Host() matcher
|
|
||||||
[acme.httpChallenge]
|
[acme.httpChallenge]
|
||||||
entryPoint = "web" # used during the challenge
|
entryPoint = "web" # used during the challenge
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Configuring Wildcard Certificates"
|
??? example "Configuring Wildcard Certificates"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.web]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
|
[entrypoints.http-tls]
|
||||||
|
address = ":443"
|
||||||
|
|
||||||
[entryPoints.http-tls]
|
|
||||||
address = ":443"
|
|
||||||
[entryPoints.https.tls] # enabling TLS
|
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "your-email@your-domain.org"
|
email = "your-email@your-domain.org"
|
||||||
storage = "acme.json"
|
storage = "acme.json"
|
||||||
entryPoint = "http-tls" # acme is enabled on http-tls
|
[acme.dnsChallenge]
|
||||||
[acme.dnsChallenge]
|
provider = "xxx"
|
||||||
provider = "xxx"
|
|
||||||
|
[[acme.domains]]
|
||||||
[[acme.domains]]
|
main = "*.mydomain.com"
|
||||||
main = "*.mydomain.com"
|
sans = ["mydomain.com"]
|
||||||
sans = ["mydomain.com"]
|
```
|
||||||
```
|
|
||||||
|
|
||||||
!!! note "Configuration Reference"
|
!!! note "Configuration Reference"
|
||||||
|
|
||||||
There are many available options for ACME. For a quick glance at what's possible, browse the [configuration reference](../reference/acme.md).
|
There are many available options for ACME. For a quick glance at what's possible, browse the [configuration reference](../reference/acme.md).
|
||||||
|
@ -65,37 +61,34 @@ Traefik can automatically generate certificates for your domains using an ACME p
|
||||||
|
|
||||||
Use the `TLS-ALPN-01` challenge to generate and renew ACME certificates by provisioning a TLS certificate.
|
Use the `TLS-ALPN-01` challenge to generate and renew ACME certificates by provisioning a TLS certificate.
|
||||||
|
|
||||||
??? example "Using an EntryPoint Called https for the `tlsChallenge`"
|
??? example "Configuring the `tlsChallenge`"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
[acme.tlsChallenge]
|
||||||
entryPoint = "https"
|
|
||||||
[acme.tlsChallenge]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72), when using the `TLS-ALPN-01` challenge, `acme.entryPoint` must be reachable by Let's Encrypt through port 443.
|
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72), when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encrypt through port 443.
|
||||||
|
|
||||||
#### `httpChallenge`
|
#### `httpChallenge`
|
||||||
|
|
||||||
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI.
|
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI.
|
||||||
|
|
||||||
??? example "Using an EntryPoint Called http for the `httpChallenge`"
|
??? example "Using an EntryPoint Called http for the `httpChallenge`"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
entryPoint = "https"
|
[acme.httpChallenge]
|
||||||
[acme.httpChallenge]
|
entryPoint = "http"
|
||||||
entryPoint = "http"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72), when using the `HTTP-01` challenge, `acme.httpChallenge.entryPoint` must be reachable by Let's Encrypt through port 80.
|
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72), when using the `HTTP-01` challenge, `acme.httpChallenge.entryPoint` must be reachable by Let's Encrypt through port 80.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
Redirection is fully compatible with the `HTTP-01` challenge.
|
Redirection is fully compatible with the `HTTP-01` challenge.
|
||||||
|
|
||||||
#### `dnsChallenge`
|
#### `dnsChallenge`
|
||||||
|
|
||||||
|
@ -105,20 +98,20 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
[acme.dnsChallenge]
|
[acme.dnsChallenge]
|
||||||
provider = "digitalocean"
|
provider = "digitalocean"
|
||||||
delayBeforeCheck = 0
|
delayBeforeCheck = 0
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! important
|
!!! important
|
||||||
A `provider` is mandatory.
|
A `provider` is mandatory.
|
||||||
|
|
||||||
??? list "Supported Providers"
|
??? list "Supported Providers"
|
||||||
|
|
||||||
Here is a list of supported `providers`, that can automate the DNS verification, along with the required environment variables and their [wildcard & root domain support](#wildcard-domains).
|
Here is a list of supported `providers`, that can automate the DNS verification, along with the required environment variables and their [wildcard & root domain support](#wildcard-domains).
|
||||||
Do not hesitate to complete it.
|
Do not hesitate to complete it.
|
||||||
|
|
||||||
| Provider Name | Provider Code | Environment Variables | Wildcard & Root Domain Support |
|
| Provider Name | Provider Code | Environment Variables | Wildcard & Root Domain Support |
|
||||||
|-------------------------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|
|
|-------------------------------------------------------------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|
|
||||||
|
@ -161,19 +154,19 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||||
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | Not tested yet |
|
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | Not tested yet |
|
||||||
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | Not tested yet |
|
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | Not tested yet |
|
||||||
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | YES |
|
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | YES |
|
||||||
| [Openstack Designate](https://docs.openstack.org/designate) | `designate` | `OS_AUTH_URL`, `OS_USERNAME`, `OS_PASSWORD`, `OS_TENANT_NAME`, `OS_REGION_NAME` | YES |
|
| [Openstack Designate](https://docs.openstack.org/designate) | `designate` | `OS_AUTH_URL`, `OS_USERNAME`, `OS_PASSWORD`, `OS_TENANT_NAME`, `OS_REGION_NAME` |YES |
|
||||||
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | Not tested yet |
|
| [PowerDNS](https://www.powerdns.com) | `pdns` | `PDNS_API_KEY`, `PDNS_API_URL` | Not tested yet |
|
||||||
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | Not tested yet |
|
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | Not tested yet |
|
||||||
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | Not tested yet |
|
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | Not tested yet |
|
||||||
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | YES |
|
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | YES |
|
||||||
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | Not tested yet |
|
| [Sakura Cloud](https://cloud.sakura.ad.jp/) | `sakuracloud` | `SAKURACLOUD_ACCESS_TOKEN`, `SAKURACLOUD_ACCESS_TOKEN_SECRET` | Not tested yet |
|
||||||
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | YES |
|
| [Selectel](https://selectel.ru/en/) | `selectel` | `SELECTEL_API_TOKEN` | YES |
|
||||||
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | Not tested yet |
|
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | Not tested yet |
|
||||||
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | YES |
|
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | YES |
|
||||||
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | Not tested yet |
|
| [VegaDNS](https://github.com/shupp/VegaDNS-API) | `vegadns` | `SECRET_VEGADNS_KEY`, `SECRET_VEGADNS_SECRET`, `VEGADNS_URL` | Not tested yet |
|
||||||
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | YES |
|
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | YES |
|
||||||
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | Not tested yet |
|
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | Not tested yet |
|
||||||
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | YES |
|
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | YES |
|
||||||
|
|
||||||
- (1): more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
- (1): more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
||||||
- (2): https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
|
- (2): https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
|
||||||
|
@ -187,13 +180,13 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||||
!!! note "`resolvers`"
|
!!! note "`resolvers`"
|
||||||
|
|
||||||
Use custom DNS servers to resolve the FQDN authority.
|
Use custom DNS servers to resolve the FQDN authority.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
[acme.dnsChallenge]
|
[acme.dnsChallenge]
|
||||||
# ...
|
# ...
|
||||||
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Known Domains, SANs, and Wildcards
|
### Known Domains, SANs, and Wildcards
|
||||||
|
@ -204,15 +197,15 @@ Each domain & SAN will lead to a certificate request.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
[[acme.domains]]
|
[[acme.domains]]
|
||||||
main = "local1.com"
|
main = "local1.com"
|
||||||
sans = ["test1.local1.com", "test2.local1.com"]
|
sans = ["test1.local1.com", "test2.local1.com"]
|
||||||
[[acme.domains]]
|
[[acme.domains]]
|
||||||
main = "local2.com"
|
main = "local2.com"
|
||||||
[[acme.domains]]
|
[[acme.domains]]
|
||||||
main = "*.local3.com"
|
main = "*.local3.com"
|
||||||
sans = ["local3.com", "test1.test1.local3.com"]
|
sans = ["local3.com", "test1.test1.local3.com"]
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -229,10 +222,11 @@ As described in [Let's Encrypt's post](https://community.letsencrypt.org/t/stagi
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
[[acme.domains]]
|
[[acme.domains]]
|
||||||
main = "*.local1.com"
|
main = "*.local1.com"
|
||||||
sans = ["local1.com"]
|
sans = ["local1.com"]
|
||||||
|
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -241,7 +235,7 @@ As described in [Let's Encrypt's post](https://community.letsencrypt.org/t/stagi
|
||||||
|
|
||||||
!!! note "Double Wildcard Certificates"
|
!!! note "Double Wildcard Certificates"
|
||||||
It is not possible to request a double wildcard certificate for a domain (for example `*.*.local.com`).
|
It is not possible to request a double wildcard certificate for a domain (for example `*.*.local.com`).
|
||||||
|
|
||||||
Due to an ACME limitation it is not possible to define wildcards in SANs (alternative domains).
|
Due to an ACME limitation it is not possible to define wildcards in SANs (alternative domains).
|
||||||
Thus, the wildcard domain has to be defined as a main domain.
|
Thus, the wildcard domain has to be defined as a main domain.
|
||||||
Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 `DNS-01` challenges are executed.
|
Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 `DNS-01` challenges are executed.
|
||||||
|
@ -256,22 +250,22 @@ The [Supported `provider` table](#dnschallenge) indicates if they allow generati
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### onHostRule
|
### onHostRule
|
||||||
|
|
||||||
Enable certificate generation on [routers](routers.md) `Host` rules (for routers active on the `acme.entryPoint`).
|
Enable certificate generation on [routers](../routing/routers/index.md) `Host` & `HostSNI` rules.
|
||||||
|
|
||||||
This will request a certificate from Let's Encrypt for each router with a Host rule.
|
This will request a certificate from Let's Encrypt for each router with a Host rule.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
onHostRule = true
|
onHostRule = true
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note "Multiple Hosts in a Rule"
|
!!! note "Multiple Hosts in a Rule"
|
||||||
|
@ -286,9 +280,9 @@ The `storage` option sets the location where your ACME certificates are saved to
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
# ...
|
# ...
|
||||||
storage = "acme.json"
|
storage = "acme.json"
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
The value can refer to two kinds of storage:
|
The value can refer to two kinds of storage:
|
||||||
|
@ -315,7 +309,7 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||||
|
|
||||||
#### In a a Key Value Store Entry
|
#### In a a Key Value Store Entry
|
||||||
|
|
||||||
ACME certificates can be stored in a key-value store entry.
|
ACME certificates can be stored in a key-value store entry.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
storage = "traefik/acme/account"
|
storage = "traefik/acme/account"
|
145
docs/content/https-tls/overview.md
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
# HTTPS & TLS
|
||||||
|
|
||||||
|
Traefik supports HTTPS & TLS, and is able to accept new certificates / updates over time (without being restarted).
|
||||||
|
TLS is enabled at the [router](../routing/routers/index.md) level, but some options are configured in dedicated sections (`tlsOptions` & `tlsStores`) described in this section.
|
||||||
|
|
||||||
|
## Configuration Example
|
||||||
|
|
||||||
|
??? example "Configuring a Default Certificate"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsStores]
|
||||||
|
[tlsStores.default]
|
||||||
|
[tlsStores.default.defaultCertificate]
|
||||||
|
certFile = "path/to/cert.crt"
|
||||||
|
keyFile = "path/to/cert.key"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Configuring a Minimum TLS Version"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.default]
|
||||||
|
minVersion = "VersionTLS12"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Defining Certificates"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[tls]]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "/path/to/domain.cert"
|
||||||
|
keyFile = "/path/to/domain.key"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "/path/to/other-domain.cert"
|
||||||
|
keyFile = "/path/to/other-domain.key"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! important "File Provider Only"
|
||||||
|
|
||||||
|
In the above example, we've used the [file provider](../providers/file.md) to handle the TLS configuration (tlsStores, tlsOptions, and TLS certificates).
|
||||||
|
In its current alpha version, it is the only available method to configure these elements.
|
||||||
|
Of course, these options are hot reloaded and can be updated at runtime (they belong to the [dynamic configuration](../getting-started/configuration-overview.md)).
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### Dynamic Certificates
|
||||||
|
|
||||||
|
To add / remove TLS certificates while Traefik is running, the [file provider](../providers/file.md) supports Dynamic TLS certificates in its `[[tls]]` section.
|
||||||
|
|
||||||
|
!!! example "Defining Certificates"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[tls]]
|
||||||
|
stores = ["default"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "/path/to/domain.cert"
|
||||||
|
keyFile = "/path/to/domain.key"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
stores = ["default"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "/path/to/other-domain.cert"
|
||||||
|
keyFile = "/path/to/other-domain.key"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? note "Stores"
|
||||||
|
|
||||||
|
During the alpha version, the stores option will be ignored and be automatically set to ["default"].
|
||||||
|
|
||||||
|
### Mutual Authentication
|
||||||
|
|
||||||
|
Traefik supports both optional and non optional (defaut value) mutual authentication.
|
||||||
|
|
||||||
|
- When `optional = false`, Traefik accepts connections only from client presenting a certificate signed by a CA listed in `ClientCA.files`.
|
||||||
|
- When `optional = true`, Traefik authorizes connections from client presenting a certificate signed by an unknown CA.
|
||||||
|
|
||||||
|
!!! example "Non Optional Mutual Authentication"
|
||||||
|
|
||||||
|
In the following example, both `snitest.com` and `snitest.org` will require client certificates.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.default]
|
||||||
|
[tlsOptions.default.ClientCA]
|
||||||
|
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||||
|
optional = false
|
||||||
|
```
|
||||||
|
|
||||||
|
??? note "ClientCA.files"
|
||||||
|
|
||||||
|
You can use a file per `CA:s`, or a single file containing multiple `CA:s` (in `PEM` format).
|
||||||
|
|
||||||
|
`ClientCA.files` is not optional: every client will have to present a valid certificate. (This requirement will apply to every server certificate declared in the entrypoint.)
|
||||||
|
|
||||||
|
### Minimum TLS Version
|
||||||
|
|
||||||
|
!!! example "Min TLS version & [cipherSuites](https://godoc.org/crypto/tls#pkg-constants)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.default]
|
||||||
|
minVersion = "VersionTLS12"
|
||||||
|
cipherSuites = [
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Strict SNI Checking
|
||||||
|
|
||||||
|
With strict SNI checking, Traefik won't allow connections without a matching certificate.
|
||||||
|
|
||||||
|
!!! example "Strict SNI"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.default]
|
||||||
|
sniStrict = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Default Certificate
|
||||||
|
|
||||||
|
Traefik can use a default certificate for connections without a SNI, or without a matching domain.
|
||||||
|
|
||||||
|
If no default certificate is provided, Traefik generates and uses a self-signed certificate.
|
||||||
|
|
||||||
|
!!! example "Setting a Default Certificate"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tlsStores]
|
||||||
|
[tlsStores.default]
|
||||||
|
[tlsStores.default.defaultCertificate]
|
||||||
|
certFile = "path/to/cert.crt"
|
||||||
|
keyFile = "path/to/cert.key"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? note "Only One Default Certificate"
|
||||||
|
|
||||||
|
There can only be one `defaultCertificate` per tlsOptions.
|
||||||
|
|
||||||
|
??? note "Default TLS Store"
|
||||||
|
|
||||||
|
During the alpha version, there is only one globally available TLS Store (`default`).
|
|
@ -1,2 +1,2 @@
|
||||||
!!! info "More On Routers"
|
!!! info "More On Routers"
|
||||||
Learn more about routers and their configuration options in the [dedicated section](../routing/routers.md).
|
Learn more about routers and their configuration options in the [dedicated section](../routing/routers/index.md).
|
||||||
|
|
|
@ -12,8 +12,8 @@ The AddPrefix middleware updates the URL Path of the request before forwarding i
|
||||||
??? example "File -- Prefixing with /foo"
|
??? example "File -- Prefixing with /foo"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.add-foo.AddPrefix]
|
[http.middlewares.add-foo.AddPrefix]
|
||||||
prefix = "/foo"
|
prefix = "/foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ The AddPrefix middleware updates the URL Path of the request before forwarding i
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.add-bar.addprefix.prefix=/bar"
|
- "traefik.http.middlewares.add-bar.addprefix.prefix=/bar"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -12,8 +12,8 @@ The BasicAuth middleware is a quick way to restrict access to your services to k
|
||||||
??? example "File -- Declaring the user list"
|
??? example "File -- Declaring the user list"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-auth.basicauth]
|
[http.middlewares.test-auth.basicauth]
|
||||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||||
```
|
```
|
||||||
|
@ -24,7 +24,7 @@ The BasicAuth middleware is a quick way to restrict access to your services to k
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.declared-users-only.basicauth.usersFile=path-to-file.ext",
|
- "traefik.http.middlewares.declared-users-only.basicauth.usersFile=path-to-file.ext",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
@ -73,7 +73,7 @@ You can customize the header field for the authenticated user using the `headerF
|
||||||
??? example "File -- Passing Authenticated Users to Services Via Headers"
|
??? example "File -- Passing Authenticated Users to Services Via Headers"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares.my-auth.basicauth]
|
[http.middlewares.my-auth.basicauth]
|
||||||
usersFile = "path-to-file.ext"
|
usersFile = "path-to-file.ext"
|
||||||
headerField = "X-WebAuth-User" # header for the authenticated user
|
headerField = "X-WebAuth-User" # header for the authenticated user
|
||||||
```
|
```
|
||||||
|
|
|
@ -16,8 +16,8 @@ This can help services deal with large data (multipart/form-data for example), a
|
||||||
??? example "File -- Sets the maximum request body to 2Mb"
|
??? example "File -- Sets the maximum request body to 2Mb"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.2Mb-limit.buffering]
|
[http.middlewares.2Mb-limit.buffering]
|
||||||
maxRequestBodyBytes = 250000
|
maxRequestBodyBytes = 250000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ This can help services deal with large data (multipart/form-data for example), a
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.1Mb-memory.buffering.memRequestBodyBytes=125000",
|
- "traefik.http.middlewares.1Mb-memory.buffering.memRequestBodyBytes=125000",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -14,27 +14,27 @@ It makes reusing the same groups easier.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# ...
|
# ...
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
middlewares = ["secured"]
|
middlewares = ["secured"]
|
||||||
rule = "Host: mydomain"
|
rule = "Host: mydomain"
|
||||||
|
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.secured.Chain]
|
[http.middlewares.secured.Chain]
|
||||||
middlewares = ["https-only", "known-ips", "auth-users"]
|
middlewares = ["https-only", "known-ips", "auth-users"]
|
||||||
|
|
||||||
[Middlewares.auth-users.BasicAuth]
|
[http.middlewares.auth-users.BasicAuth]
|
||||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
||||||
[Middlewares.https-only.SchemeRedirect]
|
[http.middlewares.https-only.SchemeRedirect]
|
||||||
scheme = "https"
|
scheme = "https"
|
||||||
[Middlewares.known-ips.ipWhiteList]
|
[http.middlewares.known-ips.ipWhiteList]
|
||||||
sourceRange = ["192.168.1.7", "x.x.x.x", "x.x.x.x"]
|
sourceRange = ["192.168.1.7", "x.x.x.x", "x.x.x.x"]
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.service1]
|
[http.services.service1]
|
||||||
[Services.service1.LoadBalancer]
|
[http.services.service1.LoadBalancer]
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:80"
|
URL = "http://127.0.0.1:80"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
```
|
```
|
||||||
|
|
|
@ -26,8 +26,8 @@ To assess if your system is healthy, the circuit breaker constantly monitors the
|
||||||
??? example "Latency Check -- Using Toml"
|
??? example "Latency Check -- Using Toml"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.latency-check.circuitbreaker]
|
[http.middlewares.latency-check.circuitbreaker]
|
||||||
expression = "LatencyAtQuantileMS(50.0) > 100"
|
expression = "LatencyAtQuantileMS(50.0) > 100"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ To assess if your system is healthy, the circuit breaker constantly monitors the
|
||||||
container-definition:
|
container-definition:
|
||||||
image: image-name
|
image: image-name
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Possible States
|
## Possible States
|
||||||
|
|
|
@ -12,8 +12,8 @@ The Compress middleware enables the gzip compression.
|
||||||
??? example "File -- enable gzip compression"
|
??? example "File -- enable gzip compression"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-compress.Compress]
|
[http.middlewares.test-compress.Compress]
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Docker -- enable gzip compression"
|
??? example "Docker -- enable gzip compression"
|
||||||
|
@ -22,7 +22,7 @@ The Compress middleware enables the gzip compression.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.test-compress.compress=true",
|
- "traefik.http.middlewares.test-compress.compress=true",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
|
@ -12,8 +12,8 @@ The DigestAuth middleware is a quick way to restrict access to your services to
|
||||||
??? example "File -- Declaring the user list"
|
??? example "File -- Declaring the user list"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-auth.digestauth]
|
[http.middlewares.test-auth.digestauth]
|
||||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ The DigestAuth middleware is a quick way to restrict access to your services to
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext",
|
- "traefik.http.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext",
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
|
@ -68,7 +68,7 @@ You can customize the header field for the authenticated user using the `headerF
|
||||||
??? example "File -- Passing Authenticated Users to Services Via Headers"
|
??? example "File -- Passing Authenticated Users to Services Via Headers"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares.my-auth.digestauth]
|
[http.middlewares.my-auth.digestauth]
|
||||||
usersFile = "path-to-file.ext"
|
usersFile = "path-to-file.ext"
|
||||||
headerField = "X-WebAuth-User" # header for the authenticated user
|
headerField = "X-WebAuth-User" # header for the authenticated user
|
||||||
```
|
```
|
||||||
|
|
|
@ -15,18 +15,18 @@ The ErrorPage middleware returns a custom page in lieu of the default, according
|
||||||
??? example "File -- Custom Error Page for 5XX"
|
??? example "File -- Custom Error Page for 5XX"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "my-service"
|
Service = "my-service"
|
||||||
Rule = Host(`my-domain`)
|
Rule = Host(`my-domain`)
|
||||||
|
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.5XX-errors.Errors]
|
[http.middlewares.5XX-errors.Errors]
|
||||||
status = ["500-599"]
|
status = ["500-599"]
|
||||||
service = "error-handler-service"
|
service = "error-handler-service"
|
||||||
query = "/error.html"
|
query = "/error.html"
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
# ... definition of error-handler-service and my-service
|
# ... definition of error-handler-service and my-service
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ The ErrorPage middleware returns a custom page in lieu of the default, according
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.test-errorpage.errors.status=500-599",
|
- "traefik.http.middlewares.test-errorpage.errors.status=500-599",
|
||||||
- "traefik.middlewares.test-errorpage.errors.service=serviceError",
|
- "traefik.http.middlewares.test-errorpage.errors.service=serviceError",
|
||||||
- "traefik.middlewares.test-errorpage.errors.query=/{status}.html",
|
- "traefik.http.middlewares.test-errorpage.errors.query=/{status}.html",
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@ Otherwise, the response from the authentication server is returned.
|
||||||
??? example "File -- Forward authentication to authserver.com"
|
??? example "File -- Forward authentication to authserver.com"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-auth.forwardauth]
|
[http.middlewares.test-auth.forwardauth]
|
||||||
address = "https://authserver.com/auth"
|
address = "https://authserver.com/auth"
|
||||||
trustForwardHeader = true
|
trustForwardHeader = true
|
||||||
authResponseHeaders = ["X-Auth-User", "X-Secret"]
|
authResponseHeaders = ["X-Auth-User", "X-Secret"]
|
||||||
|
|
||||||
[Middlewares.test-auth.forwardauth.tls]
|
[http.middlewares.test-auth.forwardauth.tls]
|
||||||
ca = "path/to/local.crt"
|
ca = "path/to/local.crt"
|
||||||
caOptional = true
|
caOptional = true
|
||||||
cert = "path/to/foo.cert"
|
cert = "path/to/foo.cert"
|
||||||
|
@ -33,14 +33,14 @@ Otherwise, the response from the authentication server is returned.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.Address=https://authserver.com/auth"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.Address=https://authserver.com/auth"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.AuthResponseHeaders=X-Auth-User, X-Secret"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.AuthResponseHeaders=X-Auth-User, X-Secret"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TLS.CA=path/to/local.crt"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CA=path/to/local.crt"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TLS.CAOptional=true"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CAOptional=true"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TLS.Cert=path/to/foo.cert"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Cert=path/to/foo.cert"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TLS.InsecureSkipVerify=true"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.InsecureSkipVerify=true"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TLS.Key=path/to/foo.key"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Key=path/to/foo.key"
|
||||||
- "traefik.Middlewares.test-auth.ForwardAuth.TrustForwardHeader=true"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TrustForwardHeader=true"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,11 @@ Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response
|
||||||
??? example "File"
|
??? example "File"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.testHeader.headers]
|
[http.middlewares.testHeader.headers]
|
||||||
[Middlewares.testHeader.headers.CustomRequestHeaders]
|
[http.middlewares.testHeader.headers.CustomRequestHeaders]
|
||||||
X-Script-Name = "test"
|
X-Script-Name = "test"
|
||||||
[Middlewares.testHeader.headers.CustomResponseHeaders]
|
[http.middlewares.testHeader.headers.CustomResponseHeaders]
|
||||||
X-Custom-Response-Header = "True"
|
X-Custom-Response-Header = "True"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
- "traefik.http.middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
||||||
- "traefik.Middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
- "traefik.http.middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
||||||
```
|
```
|
||||||
|
|
||||||
### Adding and Removing Headers
|
### Adding and Removing Headers
|
||||||
|
@ -41,11 +41,11 @@ Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response
|
||||||
??? example "File"
|
??? example "File"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.testHeader.headers]
|
[http.middlewares.testHeader.headers]
|
||||||
[Middlewares.testHeader.headers.CustomRequestHeaders]
|
[http.middlewares.testHeader.headers.CustomRequestHeaders]
|
||||||
X-Script-Name = "test"
|
X-Script-Name = "test"
|
||||||
[Middlewares.testHeader.headers.CustomResponseHeaders]
|
[http.middlewares.testHeader.headers.CustomResponseHeaders]
|
||||||
X-Custom-Response-Header = "True"
|
X-Custom-Response-Header = "True"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
- "traefik.http.middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
||||||
- "traefik.Middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
- "traefik.http.middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Security Headers
|
### Using Security Headers
|
||||||
|
@ -67,8 +67,8 @@ This functionality allows for some easy security features to quickly be set.
|
||||||
??? example "File"
|
??? example "File"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.testHeader.headers]
|
[http.middlewares.testHeader.headers]
|
||||||
FrameDeny = true
|
FrameDeny = true
|
||||||
SSLRedirect = true
|
SSLRedirect = true
|
||||||
```
|
```
|
||||||
|
@ -79,8 +79,8 @@ This functionality allows for some easy security features to quickly be set.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.testHeader.Headers.FrameDeny=true",
|
- "traefik.http.middlewares.testHeader.Headers.FrameDeny=true",
|
||||||
- "traefik.Middlewares.testHeader.Headers.SSLRedirect=true",
|
- "traefik.http.middlewares.testHeader.Headers.SSLRedirect=true",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -12,8 +12,8 @@ IPWhitelist accepts / refuses requests based on the client IP.
|
||||||
??? example "File -- Accepts request from defined IP"
|
??? example "File -- Accepts request from defined IP"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-ipwhitelist.ipWhiteList]
|
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
||||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ IPWhitelist accepts / refuses requests based on the client IP.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.Middleware9.IPWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
- "traefik.http.middlewares.Middleware9.IPWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
@ -55,10 +55,10 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
??? example "File -- Whitelisting Based on `X-Forwarded-For` with `depth=2`"
|
??? example "File -- Whitelisting Based on `X-Forwarded-For` with `depth=2`"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-ipwhitelist.ipWhiteList]
|
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
||||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
[Middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
||||||
depth = 2
|
depth = 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.testIPwhitelist.ipWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
- "traefik.http.middlewares.testIPwhitelist.ipWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
||||||
- "traefik.middlewares.testIPwhitelist.ipwhitelist.ipstrategy.depth=2"
|
- "traefik.http.middlewares.testIPwhitelist.ipwhitelist.ipstrategy.depth=2"
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
@ -97,9 +97,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
??? example "File -- Exclude from `X-Forwarded-For`"
|
??? example "File -- Exclude from `X-Forwarded-For`"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-ipwhitelist.ipWhiteList]
|
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
||||||
[Middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -109,5 +109,5 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.testIPwhitelist.ipwhitelist.ipstrategy.excludedIPs=127.0.0.1/32, 192.168.1.7"
|
- "traefik.http.middlewares.testIPwhitelist.ipwhitelist.ipstrategy.excludedIPs=127.0.0.1/32, 192.168.1.7"
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,8 +12,8 @@ To proactively prevent services from being overwhelmed with high load, a maximum
|
||||||
??? example "File -- Limiting to 10 simultaneous connections"
|
??? example "File -- Limiting to 10 simultaneous connections"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-maxconn.maxconn]
|
[http.middlewares.test-maxconn.maxconn]
|
||||||
amount = 10
|
amount = 10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ To proactively prevent services from being overwhelmed with high load, a maximum
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.test-maxconn.maxconn.amount=10"
|
- "traefik.http.middlewares.test-maxconn.maxconn.amount=10"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -5,35 +5,35 @@ Tweaking the Request
|
||||||
|
|
||||||
![Overview](../assets/img/middleware/overview.png)
|
![Overview](../assets/img/middleware/overview.png)
|
||||||
|
|
||||||
Attached to the routers, pieces of middleware are a mean of tweaking the requests before they are sent to your [service](../routing/services.md) (or before the answer from the services are sent to the clients).
|
Attached to the routers, pieces of middleware are a mean of tweaking the requests before they are sent to your [service](../routing/services/index.md) (or before the answer from the services are sent to the clients).
|
||||||
|
|
||||||
There are many different available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
|
There are many different available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on.
|
||||||
|
|
||||||
Pieces of middleware can be combined in chains to fit every scenario.
|
Pieces of middleware can be combined in chains to fit every scenario.
|
||||||
|
|
||||||
## Configuration Example
|
## Configuration Example
|
||||||
|
|
||||||
??? example "As Toml Configuration File"
|
??? example "As Toml Configuration File"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "myService"
|
Service = "myService"
|
||||||
Middlewares = ["foo-add-prefix"]
|
Middlewares = ["foo-add-prefix"]
|
||||||
Rule = "Host: example.com"
|
Rule = "Host: example.com"
|
||||||
|
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.foo-add-prefix.AddPrefix]
|
[http.middlewares.foo-add-prefix.AddPrefix]
|
||||||
prefix = "/foo"
|
prefix = "/foo"
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.service1]
|
[http.services.service1]
|
||||||
[Services.service1.LoadBalancer]
|
[http.services.service1.LoadBalancer]
|
||||||
|
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:80"
|
URL = "http://127.0.0.1:80"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
```
|
```
|
||||||
|
@ -45,7 +45,7 @@ Pieces of middleware can be combined in chains to fit every scenario.
|
||||||
whoami:
|
whoami:
|
||||||
image: containous/whoami # A container that exposes an API to show its IP address
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.foo-add-prefix.addprefix.prefix=/foo",
|
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Advanced Configuration
|
## Advanced Configuration
|
||||||
|
@ -58,25 +58,25 @@ If you use multiple `providers` and wish to reference a middleware declared in a
|
||||||
??? abstract "Referencing a Middleware from Another Provider"
|
??? abstract "Referencing a Middleware from Another Provider"
|
||||||
|
|
||||||
Declaring the add-foo-prefix in the file provider.
|
Declaring the add-foo-prefix in the file provider.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.add-foo-prefix.AddPrefix]
|
[http.middlewares.add-foo-prefix.AddPrefix]
|
||||||
prefix = "/foo"
|
prefix = "/foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
Using the add-foo-prefix middleware from docker.
|
Using the add-foo-prefix middleware from docker.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
your-container: #
|
your-container: #
|
||||||
image: your-docker-image
|
image: your-docker-image
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
# Attach file.add-foo-prefix middleware (declared in file)
|
# Attach file.add-foo-prefix middleware (declared in file)
|
||||||
- "traefik.routers.middlewares=file.add-foo-prefix",
|
- "traefik.http.routers.middlewares=file.add-foo-prefix",
|
||||||
```
|
```
|
||||||
|
|
||||||
## Available Middlewares
|
## Available Middlewares
|
||||||
|
|
|
@ -12,8 +12,8 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
??? example "File -- Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
|
??? example "File -- Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-passtlsclientcert.passtlsclientcert]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
||||||
pem = true
|
pem = true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,19 +23,19 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.Middleware11.passtlsclientcert.pem=true"
|
- "traefik.http.middlewares.Middleware11.passtlsclientcert.pem=true"
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "File -- Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header"
|
??? example "File -- Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-passtlsclientcert.passtlsclientcert]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
||||||
[Middlewares.test-passtlsclientcert.passtlsclientcert.info]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert.info]
|
||||||
notAfter = true
|
notAfter = true
|
||||||
notBefore = true
|
notBefore = true
|
||||||
sans = true
|
sans = true
|
||||||
[Middlewares.test-passtlsclientcert.passtlsclientcert.info.subject]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject]
|
||||||
country = true
|
country = true
|
||||||
province = true
|
province = true
|
||||||
locality = true
|
locality = true
|
||||||
|
@ -43,7 +43,7 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
commonName = true
|
commonName = true
|
||||||
serialNumber = true
|
serialNumber = true
|
||||||
domainComponent = true
|
domainComponent = true
|
||||||
[Middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer]
|
||||||
country = true
|
country = true
|
||||||
province = true
|
province = true
|
||||||
locality = true
|
locality = true
|
||||||
|
@ -59,23 +59,23 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
||||||
- "traefik.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -12,11 +12,11 @@ The RateLimit middleware ensures that services will receive a _fair_ number of r
|
||||||
??? example "Limit to 100 requests every 10 seconds (with a possible burst of 200)"
|
??? example "Limit to 100 requests every 10 seconds (with a possible burst of 200)"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.fair-ratelimit.ratelimit]
|
[http.middlewares.fair-ratelimit.ratelimit]
|
||||||
extractorfunc = "client.ip"
|
extractorfunc = "client.ip"
|
||||||
|
|
||||||
[middlewares.fair-ratelimit.ratelimit.rateset1]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
||||||
period = "10s"
|
period = "10s"
|
||||||
average = 100
|
average = 100
|
||||||
burst = 200
|
burst = 200
|
||||||
|
@ -25,16 +25,16 @@ The RateLimit middleware ensures that services will receive a _fair_ number of r
|
||||||
??? example "Combine multiple limits"
|
??? example "Combine multiple limits"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.fair-ratelimit.ratelimit]
|
[http.middlewares.fair-ratelimit.ratelimit]
|
||||||
extractorfunc = "client.ip"
|
extractorfunc = "client.ip"
|
||||||
|
|
||||||
[middlewares.fair-ratelimit.ratelimit.rateset1]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
||||||
period = "10s"
|
period = "10s"
|
||||||
average = 100
|
average = 100
|
||||||
burst = 200
|
burst = 200
|
||||||
|
|
||||||
[middlewares.fair-ratelimit.ratelimit.rateset2]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset2]
|
||||||
period = "3s"
|
period = "3s"
|
||||||
average = 5
|
average = 5
|
||||||
burst = 10
|
burst = 10
|
||||||
|
|
|
@ -12,8 +12,8 @@ RegexRedirect redirect a request from an url to another with regex matching and
|
||||||
??? example "File -- Redirect with domain replacement"
|
??? example "File -- Redirect with domain replacement"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-redirectregex.redirectregex]
|
[http.middlewares.test-redirectregex.redirectregex]
|
||||||
regex = "^http://localhost/(.*)"
|
regex = "^http://localhost/(.*)"
|
||||||
replacement = "http://mydomain/$1"
|
replacement = "http://mydomain/$1"
|
||||||
```
|
```
|
||||||
|
@ -24,8 +24,8 @@ RegexRedirect redirect a request from an url to another with regex matching and
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
|
- "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)"
|
||||||
- "traefik.Middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$1"
|
- "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$1"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -12,8 +12,8 @@ RegexRedirect redirect request from a scheme to another.
|
||||||
??? example "File -- Redirect to https"
|
??? example "File -- Redirect to https"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-redirectscheme.redirectscheme]
|
[http.middlewares.test-redirectscheme.redirectscheme]
|
||||||
scheme = "https"
|
scheme = "https"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ RegexRedirect redirect request from a scheme to another.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.Middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -12,8 +12,8 @@ Replace the path of the request url.
|
||||||
??? example "File -- Replace the path by /foo"
|
??? example "File -- Replace the path by /foo"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Middlewares]
|
[http.middlewares]
|
||||||
[Middlewares.test-replacepath.ReplacePath]
|
[http.middlewares.test-replacepath.ReplacePath]
|
||||||
path = "/foo"
|
path = "/foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ Replace the path of the request url.
|
||||||
a-container:
|
a-container:
|
||||||
image: a-container-image
|
image: a-container-image
|
||||||
labels:
|
labels:
|
||||||
- "traefik.middlewares.test-replacepath.replacepath.path=/foo"
|
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
|
@ -8,8 +8,8 @@ Checking the Health of Your Traefik Instances
|
||||||
??? example "Enabling /ping on the http EntryPoint"
|
??? example "Enabling /ping on the http EntryPoint"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entrypoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
|
@ -19,13 +19,13 @@ Checking the Health of Your Traefik Instances
|
||||||
??? example "Enabling /ping on the https EntryPoint"
|
??? example "Enabling /ping on the https EntryPoint"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
entryPoint = "https"
|
entryPoint = "https"
|
||||||
|
@ -34,11 +34,11 @@ Checking the Health of Your Traefik Instances
|
||||||
??? example "Enabling /ping on a dedicated EntryPoint"
|
??? example "Enabling /ping on a dedicated EntryPoint"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.ping]
|
[entrypoints.ping]
|
||||||
address = ":8082"
|
address = ":8082"
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Traefik & Docker
|
# Traefik & Docker
|
||||||
|
|
||||||
A Story of Labels & Containers
|
A Story of Labels & Containers
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
|
||||||
![Docker](../assets/img/providers/docker.png)
|
![Docker](../assets/img/providers/docker.png)
|
||||||
|
|
||||||
|
@ -15,27 +15,27 @@ Attach labels to your containers and let Traefik do the rest!
|
||||||
??? example "Configuring Docker & Deploying / Exposing Services"
|
??? example "Configuring Docker & Deploying / Exposing Services"
|
||||||
|
|
||||||
Enabling the docker provider
|
Enabling the docker provider
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[docker]
|
[docker]
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
```
|
```
|
||||||
|
|
||||||
Attaching labels to containers (in your docker compose file)
|
Attaching labels to containers (in your docker compose file)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
my-container:
|
my-container:
|
||||||
# ...
|
# ...
|
||||||
labels:
|
labels:
|
||||||
- traefik.services.my-container.rule=Host(my-domain)
|
- traefik.http.services.my-container.rule=Host(my-domain)
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
||||||
|
|
||||||
Enabling the docker provider (Swarm Mode)
|
Enabling the docker provider (Swarm Mode)
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[docker]
|
[docker]
|
||||||
# swarm classic (1.12-)
|
# swarm classic (1.12-)
|
||||||
|
@ -44,18 +44,18 @@ Attach labels to your containers and let Traefik do the rest!
|
||||||
endpoint = "tcp://127.0.0.1:2377"
|
endpoint = "tcp://127.0.0.1:2377"
|
||||||
swarmMode = true
|
swarmMode = true
|
||||||
```
|
```
|
||||||
|
|
||||||
Attaching labels to containers (in your docker compose file)
|
Attaching labels to containers (in your docker compose file)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
my-container:
|
my-container:
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
- traefik.services.my-container.rule=Host(my-domain)
|
- traefik.http.services.my-container.rule=Host(my-domain)
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! important "Labels in Docker Swarm Mode"
|
!!! important "Labels in Docker Swarm Mode"
|
||||||
If you use a compose file with the Swarm mode, labels should be defined in the `deploy` part of your service.
|
If you use a compose file with the Swarm mode, labels should be defined in the `deploy` part of your service.
|
||||||
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/#labels-1)).
|
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/#labels-1)).
|
||||||
|
@ -76,13 +76,13 @@ Traefik requires access to the docker socket to get its dynamic configuration.
|
||||||
As explained in the Docker documentation: ([Docker Daemon Attack Surface page](https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface)):
|
As explained in the Docker documentation: ([Docker Daemon Attack Surface page](https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface)):
|
||||||
|
|
||||||
`[...] only **trusted** users should be allowed to control your Docker daemon [...]`
|
`[...] only **trusted** users should be allowed to control your Docker daemon [...]`
|
||||||
|
|
||||||
!!! note "Improved Security"
|
!!! note "Improved Security"
|
||||||
|
|
||||||
[TraefikEE](https://containo.us/traefikee) solves this problem by separating the control plane (connected to Docker) and the data plane (handling the requests).
|
[TraefikEE](https://containo.us/traefikee) solves this problem by separating the control plane (connected to Docker) and the data plane (handling the requests).
|
||||||
|
|
||||||
??? tip "Resources about Docker's Security"
|
??? tip "Resources about Docker's Security"
|
||||||
|
|
||||||
- [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY)
|
- [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY)
|
||||||
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html)
|
- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html)
|
||||||
- [A thread on Stack Overflow about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623)
|
- [A thread on Stack Overflow about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623)
|
||||||
|
@ -92,20 +92,20 @@ Traefik requires access to the docker socket to get its dynamic configuration.
|
||||||
|
|
||||||
Expose the Docker socket over TCP, instead of the default Unix socket file.
|
Expose the Docker socket over TCP, instead of the default Unix socket file.
|
||||||
It allows different implementation levels of the [AAA (Authentication, Authorization, Accounting) concepts](https://en.wikipedia.org/wiki/AAA_(computer_security)), depending on your security assessment:
|
It allows different implementation levels of the [AAA (Authentication, Authorization, Accounting) concepts](https://en.wikipedia.org/wiki/AAA_(computer_security)), depending on your security assessment:
|
||||||
|
|
||||||
- Authentication with Client Certificates as described in ["Protect the Docker daemon socket."](https://docs.docker.com/engine/security/https/)
|
- Authentication with Client Certificates as described in ["Protect the Docker daemon socket."](https://docs.docker.com/engine/security/https/)
|
||||||
|
|
||||||
- Authorization with the [Docker Authorization Plugin Mechanism](https://docs.docker.com/engine/extend/plugins_authorization/)
|
- Authorization with the [Docker Authorization Plugin Mechanism](https://docs.docker.com/engine/extend/plugins_authorization/)
|
||||||
|
|
||||||
- Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik.
|
- Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik.
|
||||||
|
|
||||||
- Accounting at container level, by exposing the socket on a another container than Traefik's.
|
- Accounting at container level, by exposing the socket on a another container than Traefik's.
|
||||||
With Swarm mode, it allows scheduling of Traefik on worker nodes, with only the "socket exposer" container on the manager nodes.
|
With Swarm mode, it allows scheduling of Traefik on worker nodes, with only the "socket exposer" container on the manager nodes.
|
||||||
|
|
||||||
- Accounting at kernel level, by enforcing kernel calls with mechanisms like [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), to only allows an identified set of actions for Traefik's process (or the "socket exposer" process).
|
- Accounting at kernel level, by enforcing kernel calls with mechanisms like [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), to only allows an identified set of actions for Traefik's process (or the "socket exposer" process).
|
||||||
|
|
||||||
??? tip "Additional Resources"
|
??? tip "Additional Resources"
|
||||||
|
|
||||||
- [Traefik issue GH-4174 about security with Docker socket](https://github.com/containous/traefik/issues/4174)
|
- [Traefik issue GH-4174 about security with Docker socket](https://github.com/containous/traefik/issues/4174)
|
||||||
- [Inspecting Docker Activity with Socat](https://developers.redhat.com/blog/2015/02/25/inspecting-docker-activity-with-socat/)
|
- [Inspecting Docker Activity with Socat](https://developers.redhat.com/blog/2015/02/25/inspecting-docker-activity-with-socat/)
|
||||||
- [Letting Traefik run on Worker Nodes](https://blog.mikesir87.io/2018/07/letting-traefik-run-on-worker-nodes/)
|
- [Letting Traefik run on Worker Nodes](https://blog.mikesir87.io/2018/07/letting-traefik-run-on-worker-nodes/)
|
||||||
|
@ -113,34 +113,34 @@ Traefik requires access to the docker socket to get its dynamic configuration.
|
||||||
|
|
||||||
!!! note "Traefik & Swarm Mode"
|
!!! note "Traefik & Swarm Mode"
|
||||||
To let Traefik access the Docker Socket of the Swarm manager, it is mandatory to schedule Traefik on the Swarm manager nodes.
|
To let Traefik access the Docker Socket of the Swarm manager, it is mandatory to schedule Traefik on the Swarm manager nodes.
|
||||||
|
|
||||||
??? example "Using the docker.sock"
|
??? example "Using the docker.sock"
|
||||||
|
|
||||||
The docker-compose file shares the docker sock with the Traefik container
|
The docker-compose file shares the docker sock with the Traefik container
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik
|
image: traefik
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
```
|
```
|
||||||
|
|
||||||
We specify the docker.sock in traefik's configuration file.
|
We specify the docker.sock in traefik's configuration file.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# ...
|
# ...
|
||||||
[providers]
|
[providers]
|
||||||
[providers.docker]
|
[providers.docker]
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
```
|
```
|
||||||
|
|
||||||
### usebindportip (_Optional_, _Default=false_)
|
### usebindportip (_Optional_, _Default=false_)
|
||||||
|
|
||||||
Traefik routes requests to the IP/Port of the matching container.
|
Traefik routes requests to the IP/Port of the matching container.
|
||||||
When setting `usebindportip=true`, you tell Traefik to use the IP/Port attached to the container's _binding_ instead of its inner network IP/Port.
|
When setting `usebindportip=true`, you tell Traefik to use the IP/Port attached to the container's _binding_ instead of its inner network IP/Port.
|
||||||
|
@ -159,11 +159,11 @@ If it can't find such a binding, Traefik falls back on the internal network IP o
|
||||||
| LblPort | ExtIp:ExtPort:LblPort | ExtIp:ExtPort |
|
| LblPort | ExtIp:ExtPort:LblPort | ExtIp:ExtPort |
|
||||||
| LblPort | ExtIp:ExtPort:OtherPort | IntIp:LblPort |
|
| LblPort | ExtIp:ExtPort:OtherPort | IntIp:LblPort |
|
||||||
| LblPort | ExtIp1:ExtPort1:IntPort1 & ExtIp2:LblPort:IntPort2 | ExtIp2:LblPort |
|
| LblPort | ExtIp1:ExtPort1:IntPort1 & ExtIp2:LblPort:IntPort2 | ExtIp2:LblPort |
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
In the above table, ExtIp stands for "external IP found in the binding", IntIp stands for "internal network container's IP", ExtPort stands for "external Port found in the binding", and IntPort stands for "internal network container's port."
|
In the above table, ExtIp stands for "external IP found in the binding", IntIp stands for "internal network container's IP", ExtPort stands for "external Port found in the binding", and IntPort stands for "internal network container's port."
|
||||||
|
|
||||||
### exposedByDefault (_Optional_, _Default=true_)
|
### exposedByDefault (_Optional_, _Default=true_)
|
||||||
|
|
||||||
Expose containers by default through Traefik.
|
Expose containers by default through Traefik.
|
||||||
If set to false, containers that don't have a `traefik.enable=true` label will be ignored from the resulting routing configuration.
|
If set to false, containers that don't have a `traefik.enable=true` label will be ignored from the resulting routing configuration.
|
||||||
|
@ -193,25 +193,25 @@ Defines the polling interval (in seconds) in Swarm Mode.
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
|
||||||
Traefik creates, for each container, a corresponding [service](../routing/services.md) and [router](../routing/routers.md).
|
Traefik creates, for each container, a corresponding [service](../routing/services/index.md) and [router](../routing/routers/index.md).
|
||||||
|
|
||||||
The Service automatically gets a server per instance of the container, and the router gets a default rule attached to it, based on the container name.
|
The Service automatically gets a server per instance of the container, and the router gets a default rule attached to it, based on the container name.
|
||||||
|
|
||||||
### Routers
|
### Routers
|
||||||
|
|
||||||
To update the configuration of the Router automatically attached to the container, add labels starting with `traefik.routers.{name-of-your-choice}.` and followed by the option you want to change. For example, to change the rule, you could add the label `traefik.routers.my-container.rule=Host(my-domain)`.
|
To update the configuration of the Router automatically attached to the container, add labels starting with `traefik.routers.{name-of-your-choice}.` and followed by the option you want to change. For example, to change the rule, you could add the label `traefik.http.routers.my-container.rule=Host(my-domain)`.
|
||||||
|
|
||||||
Every [Router](../routing/routers.md) parameter can be updated this way.
|
Every [Router](../routing/routers/index.md) parameter can be updated this way.
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
|
|
||||||
To update the configuration of the Service automatically attached to the container, add labels starting with `traefik.services.{name-of-your-choice}.`, followed by the option you want to change. For example, to change the load balancer method, you'd add the label `traefik.services.{name-of-your-choice}.loadbalancer.method=drr`.
|
To update the configuration of the Service automatically attached to the container, add labels starting with `traefik.http.services.{name-of-your-choice}.`, followed by the option you want to change. For example, to change the load balancer method, you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.method=drr`.
|
||||||
|
|
||||||
Every [Service](../routing/services.md) parameter can be updated this way.
|
Every [Service](../routing/services/index.md) parameter can be updated this way.
|
||||||
|
|
||||||
### Middleware
|
### Middleware
|
||||||
|
|
||||||
You can declare pieces of middleware using labels starting with `traefik.middlewares.{name-of-your-choice}.`, followed by the middleware type/options. For example, to declare a middleware [`schemeredirect`](../middlewares/redirectscheme.md) named `my-redirect`, you'd write `traefik.middlewares.my-redirect.schemeredirect.scheme: https`.
|
You can declare pieces of middleware using labels starting with `traefik.http.middlewares.{name-of-your-choice}.`, followed by the middleware type/options. For example, to declare a middleware [`schemeredirect`](../middlewares/redirectscheme.md) named `my-redirect`, you'd write `traefik.http.middlewares.my-redirect.schemeredirect.scheme: https`.
|
||||||
|
|
||||||
??? example "Declaring and Referencing a Middleware"
|
??? example "Declaring and Referencing a Middleware"
|
||||||
|
|
||||||
|
@ -220,8 +220,8 @@ You can declare pieces of middleware using labels starting with `traefik.middlew
|
||||||
my-container:
|
my-container:
|
||||||
# ...
|
# ...
|
||||||
labels:
|
labels:
|
||||||
- traefik.middlewares.my-redirect.schemeredirect.scheme=https
|
- traefik.http.middlewares.my-redirect.schemeredirect.scheme=https
|
||||||
- traefik.routers.middlewares=my-redirect
|
- traefik.http.routers.middlewares=my-redirect
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! warning "Conflicts in Declaration"
|
!!! warning "Conflicts in Declaration"
|
||||||
|
@ -240,11 +240,11 @@ This option overrides the value of `exposedByDefault`.
|
||||||
|
|
||||||
Sets the tags for [constraints filtering](./overview.md#constraints-configuration).
|
Sets the tags for [constraints filtering](./overview.md#constraints-configuration).
|
||||||
|
|
||||||
#### traefik.docker.network
|
#### traefik.docker.network
|
||||||
|
|
||||||
Overrides the default docker network to use for connections to the container.
|
Overrides the default docker network to use for connections to the container.
|
||||||
|
|
||||||
If a container is linked to several networks, be sure to set the proper network name (you can check this with `docker inspect <container_id>`), otherwise it will randomly pick one (depending on how docker is returning them).
|
If a container is linked to several networks, be sure to set the proper network name (you can check this with `docker inspect <container_id>`), otherwise it will randomly pick one (depending on how docker is returning them).
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
When deploying a stack from a compose file `stack`, the networks defined are prefixed with `stack`.
|
When deploying a stack from a compose file `stack`, the networks defined are prefixed with `stack`.
|
||||||
|
|
|
@ -7,12 +7,11 @@ Every Options for ACME
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# Sample entrypoint configuration when using ACME.
|
# Sample entrypoint configuration when using ACME.
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
# Enable ACME (Let's Encrypt): automatic SSL.
|
# Enable ACME (Let's Encrypt): automatic SSL.
|
||||||
[acme]
|
[acme]
|
||||||
|
@ -36,12 +35,6 @@ Every Options for ACME
|
||||||
storage = "acme.json"
|
storage = "acme.json"
|
||||||
# or `storage = "traefik/acme/account"` if using KV store.
|
# or `storage = "traefik/acme/account"` if using KV store.
|
||||||
|
|
||||||
# Entrypoint to proxy acme apply certificates to.
|
|
||||||
#
|
|
||||||
# Required
|
|
||||||
#
|
|
||||||
entryPoint = "https"
|
|
||||||
|
|
||||||
# Deprecated, replaced by [acme.dnsChallenge].
|
# Deprecated, replaced by [acme.dnsChallenge].
|
||||||
#
|
#
|
||||||
# Optional.
|
# Optional.
|
||||||
|
|
|
@ -6,86 +6,21 @@ Every Options for EntryPoints
|
||||||
## TOML
|
## TOML
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
# ...
|
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
[entryPoints.http.compress]
|
|
||||||
|
|
||||||
[entryPoints.http.clientIPStrategy]
|
|
||||||
depth = 5
|
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
|
||||||
|
|
||||||
[entryPoints.http.whitelist]
|
[entrypoints.web.proxyProtocol]
|
||||||
sourceRange = ["10.42.0.0/16", "152.89.1.33/32", "afed:be44::/16"]
|
|
||||||
[entryPoints.http.whitelist.IPStrategy]
|
|
||||||
depth = 5
|
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
|
||||||
|
|
||||||
[entryPoints.http.tls]
|
|
||||||
minVersion = "VersionTLS12"
|
|
||||||
cipherSuites = [
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
|
||||||
]
|
|
||||||
[[entryPoints.http.tls.certificates]]
|
|
||||||
certFile = "path/to/my.cert"
|
|
||||||
keyFile = "path/to/my.key"
|
|
||||||
[[entryPoints.http.tls.certificates]]
|
|
||||||
certFile = "path/to/other.cert"
|
|
||||||
keyFile = "path/to/other.key"
|
|
||||||
# ...
|
|
||||||
[entryPoints.http.tls.clientCA]
|
|
||||||
files = ["path/to/ca1.crt", "path/to/ca2.crt"]
|
|
||||||
optional = false
|
|
||||||
|
|
||||||
[entryPoints.http.redirect]
|
|
||||||
entryPoint = "https"
|
|
||||||
regex = "^http://localhost/(.*)"
|
|
||||||
replacement = "http://mydomain/$1"
|
|
||||||
permanent = true
|
|
||||||
|
|
||||||
[entryPoints.http.auth]
|
|
||||||
headerField = "X-WebAuth-User"
|
|
||||||
[entryPoints.http.auth.basic]
|
|
||||||
removeHeader = true
|
|
||||||
realm = "Your realm"
|
|
||||||
users = [
|
|
||||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
|
||||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
|
||||||
]
|
|
||||||
usersFile = "/path/to/.htpasswd"
|
|
||||||
[entryPoints.http.auth.digest]
|
|
||||||
removeHeader = true
|
|
||||||
users = [
|
|
||||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
|
||||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
|
||||||
]
|
|
||||||
usersFile = "/path/to/.htdigest"
|
|
||||||
[entryPoints.http.auth.forward]
|
|
||||||
address = "https://authserver.com/auth"
|
|
||||||
trustForwardHeader = true
|
|
||||||
authResponseHeaders = ["X-Auth-User"]
|
|
||||||
[entryPoints.http.auth.forward.tls]
|
|
||||||
ca = "path/to/local.crt"
|
|
||||||
caOptional = true
|
|
||||||
cert = "path/to/foo.cert"
|
|
||||||
key = "path/to/foo.key"
|
|
||||||
insecureSkipVerify = true
|
|
||||||
|
|
||||||
[entryPoints.http.proxyProtocol]
|
|
||||||
insecure = true
|
insecure = true
|
||||||
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
||||||
|
|
||||||
[entryPoints.http.forwardedHeaders]
|
[entrypoints.web.forwardedHeaders]
|
||||||
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
trustedIPs = ["10.10.10.1", "10.10.10.2"]
|
||||||
insecure = false
|
insecure = false
|
||||||
|
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -94,38 +29,7 @@ defaultEntryPoints = ["http", "https"]
|
||||||
```ini
|
```ini
|
||||||
Name:foo
|
Name:foo
|
||||||
Address::80
|
Address::80
|
||||||
TLS:/my/path/foo.cert,/my/path/foo.key;/my/path/goo.cert,/my/path/goo.key;/my/path/hoo.cert,/my/path/hoo.key
|
|
||||||
TLS
|
|
||||||
TLS.MinVersion:VersionTLS11
|
|
||||||
TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384
|
|
||||||
TLS.SniStrict:true
|
|
||||||
TLS.DefaultCertificate.Cert:path/to/foo.cert
|
|
||||||
TLS.DefaultCertificate.Key:path/to/foo.key
|
|
||||||
CA:car
|
|
||||||
CA.Optional:true
|
|
||||||
Redirect.EntryPoint:https
|
|
||||||
Redirect.Regex:http://localhost/(.*)
|
|
||||||
Redirect.Replacement:http://mydomain/$1
|
|
||||||
Redirect.Permanent:true
|
|
||||||
Compress:true
|
|
||||||
WhiteList.SourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16
|
|
||||||
WhiteList.IPStrategy.depth:3
|
|
||||||
WhiteList.IPStrategy.ExcludedIPs:10.0.0.3/24,20.0.0.3/24
|
|
||||||
ProxyProtocol.TrustedIPs:192.168.0.1
|
ProxyProtocol.TrustedIPs:192.168.0.1
|
||||||
ProxyProtocol.Insecure:true
|
ProxyProtocol.Insecure:true
|
||||||
ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24
|
ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24
|
||||||
Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
|
|
||||||
Auth.Basic.Removeheader:true
|
|
||||||
Auth.Basic.Realm:traefik
|
|
||||||
Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e
|
|
||||||
Auth.Digest.Removeheader:true
|
|
||||||
Auth.HeaderField:X-WebAuth-User
|
|
||||||
Auth.Forward.Address:https://authserver.com/auth
|
|
||||||
Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret
|
|
||||||
Auth.Forward.TrustForwardHeader:true
|
|
||||||
Auth.Forward.TLS.CA:path/to/local.crt
|
|
||||||
Auth.Forward.TLS.CAOptional:true
|
|
||||||
Auth.Forward.TLS.Cert:path/to/foo.cert
|
|
||||||
Auth.Forward.TLS.Key:path/to/foo.key
|
|
||||||
Auth.Forward.TLS.InsecureSkipVerify:true
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -6,76 +6,39 @@ Opening Connections for Incomming Requests
|
||||||
![EntryPoints](../assets/img/entrypoints.png)
|
![EntryPoints](../assets/img/entrypoints.png)
|
||||||
|
|
||||||
Entrypoints are the network entry points into Traefik.
|
Entrypoints are the network entry points into Traefik.
|
||||||
They can be defined using:
|
They define the port which will receive the requests (whether HTTP or TCP).
|
||||||
|
|
||||||
- a port (80, 443, ...)
|
|
||||||
- SSL (Certificates, Keys, authentication with a client certificate signed by a trusted CA, ...)
|
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "HTTP only"
|
??? example "Port 80 only"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
```
|
```
|
||||||
|
|
||||||
We define an `entrypoint` called `http` that will listen on port `80`.
|
We define an `entrypoint` called `web` that will listen on port `80`.
|
||||||
|
|
||||||
??? example "HTTP & HTTPS"
|
??? example "Port 80 & 443"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[[entrypoints.web-secure.tls.certificates]]
|
||||||
certFile = "tests/traefik.crt"
|
certFile = "tests/traefik.crt"
|
||||||
keyFile = "tests/traefik.key"
|
keyFile = "tests/traefik.key"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Two entrypoints are defined: one called `http`, and the other called `https`.
|
- Two entrypoints are defined: one called `web`, and the other called `web-secure`.
|
||||||
- `http` listens on port `80`, and `https` on port `443`.
|
- `web` listens on port `80`, and `web-secure` on port `443`.
|
||||||
- We enabled SSL on `https` by giving it a certificate and a key.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
In the example, `http` and `https` are the names for the entrypoints and have nothing to do with the underlying protocol.
|
|
||||||
We could have written `entryPoints.foo` and `entryPoints.bar` instead.
|
|
||||||
|
|
||||||
!!! tip "Automatic HTTPS with ACME"
|
|
||||||
|
|
||||||
If you don't have certificate files and wish to automatically enable HTTPS, you should have a look at one of Traefik's most praised feature: [ACME & Let's Encrypt integration](./acme.md)
|
|
||||||
|
|
||||||
??? example "Client Certificate Authentication"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.ClientCA]
|
|
||||||
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
|
||||||
optional = false
|
|
||||||
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "tests/traefik.crt"
|
|
||||||
keyFile = "tests/traefik.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
- We enabled SSL on `https` by giving it a certificate and a key.
|
|
||||||
- Files containing Certificate Authorities (PEM format) were added.
|
|
||||||
|
|
||||||
!!! note "Multiple CAs"
|
|
||||||
|
|
||||||
It is possible to have multiple CA:s in the same file or keep them in separate files.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
@ -115,130 +78,6 @@ Entrypoints are part of the [static configuration](../getting-started/configurat
|
||||||
command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true'
|
command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true'
|
||||||
```
|
```
|
||||||
|
|
||||||
## TLS
|
|
||||||
|
|
||||||
### Static Certificates
|
|
||||||
|
|
||||||
To add SNI support, define `certFile` and `keyFile`.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
If you provide an empty TLS configuration, default self-signed certificates will be generated.
|
|
||||||
|
|
||||||
### Dynamic Certificates
|
|
||||||
|
|
||||||
To add / remove TLS certificates while Traefik is running, the [file provider](../providers/file.md) supports Dynamic TLS certificates in its `[[tls]]` section.
|
|
||||||
|
|
||||||
### Mutual Authentication
|
|
||||||
|
|
||||||
Traefik supports both optional and non optional (defaut value) mutual authentication.
|
|
||||||
|
|
||||||
- When `optional = false`, Traefik accepts connections only from client presenting a certificate signed by a CA listed in `ClientCA.files`.
|
|
||||||
- When `optional = true`, Traefik authorizes connections from client presenting a certificate signed by an unknown CA.
|
|
||||||
|
|
||||||
??? example "Non Optional Mutual Authentication"
|
|
||||||
|
|
||||||
In the following example, both `snitest.com` and `snitest.org` will require client certificates.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.ClientCA]
|
|
||||||
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
|
||||||
optional = false
|
|
||||||
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.org.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note "ClientCA.files"
|
|
||||||
|
|
||||||
You can use a file per `CA:s`, or a single file containing multiple `CA:s` (in `PEM` format).
|
|
||||||
|
|
||||||
`ClientCA.files` is not optional: every client will have to present a valid certificate. (This requirement will apply to every server certificate declared in the entrypoint.)
|
|
||||||
|
|
||||||
### Minimum TLS Version
|
|
||||||
|
|
||||||
??? example "Min TLS version & [cipherSuites](https://godoc.org/crypto/tls#pkg-constants)"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
minVersion = "VersionTLS12"
|
|
||||||
cipherSuites = [
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
|
||||||
]
|
|
||||||
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.org.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strict SNI Checking
|
|
||||||
|
|
||||||
With strict SNI checking, Traefik won't allow connections without a matching certificate.
|
|
||||||
|
|
||||||
??? example "Strict SNI"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
sniStrict = true
|
|
||||||
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Default Certificate
|
|
||||||
|
|
||||||
Traefik can use a default certificate for connections without an SNI, or without a matching domain.
|
|
||||||
|
|
||||||
If no default certificate is provided, Traefik generates a self-signed and use it instead.
|
|
||||||
|
|
||||||
??? example "Setting a Default Certificate"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.defaultCertificate]
|
|
||||||
certFile = "integration/fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "integration/fixtures/https/snitest.com.key"
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note "Only One Default Certificate"
|
|
||||||
There can only be one `defaultCertificate` per entrypoint.
|
|
||||||
|
|
||||||
## ProxyProtocol
|
## ProxyProtocol
|
||||||
|
|
||||||
Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt).
|
Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt).
|
||||||
|
@ -246,11 +85,11 @@ Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-
|
||||||
??? example "Enabling Proxy Protocol with Trusted IPs"
|
??? example "Enabling Proxy Protocol with Trusted IPs"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.http.proxyProtocol]
|
[entrypoints.web.proxyProtocol]
|
||||||
trustedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
trustedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -261,11 +100,11 @@ Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-
|
||||||
In a test environments, you can configure Traefik to trust every incomming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect)
|
In a test environments, you can configure Traefik to trust every incomming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect)
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.http.proxyProtocol]
|
[entrypoints.web.proxyProtocol]
|
||||||
insecure = true
|
insecure = true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -281,21 +120,21 @@ You can configure Traefik to trust the forwarded headers information (`X-Forward
|
||||||
??? example "Trusting Forwarded Headers from specific IPs"
|
??? example "Trusting Forwarded Headers from specific IPs"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.http.forwardedHeaders]
|
[entrypoints.web.forwardedHeaders]
|
||||||
trustedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
trustedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Insecure Mode -- Always Trusting Forwarded Headers"
|
??? example "Insecure Mode -- Always Trusting Forwarded Headers"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[entryPoints.http.forwardedHeaders]
|
[entrypoints.web.forwardedHeaders]
|
||||||
insecure = true
|
insecure = true
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,51 +5,95 @@ What's Happening to the Requests?
|
||||||
|
|
||||||
Let's zoom on Traefik's architecture and talk about the components that enable the routes to be created.
|
Let's zoom on Traefik's architecture and talk about the components that enable the routes to be created.
|
||||||
|
|
||||||
First, when you start Traefik, you define [entrypoints](./entrypoints.md) (in their most basic forms, they are port numbers).
|
First, when you start Traefik, you define [entrypoints](../entrypoints) (in their most basic forms, they are port numbers).
|
||||||
Then, connected to these entrypoints, [routers](./routers.md) analyze the incoming requests to see if they match a set of [rules](../routers#rule).
|
Then, connected to these entrypoints, [routers](../routers) analyze the incoming requests to see if they match a set of [rules](../routers#rule).
|
||||||
If they do, the router might transform the request using pieces of [middleware](../middlewares/overview.md) before forwarding them to your [services](./services.md).
|
If they do, the router might transform the request using pieces of [middleware](../middlewares/overview.md) before forwarding them to your [services](./services/index.md).
|
||||||
|
|
||||||
![Architecture](../assets/img/architecture-overview.png)
|
![Architecture](../assets/img/architecture-overview.png)
|
||||||
|
|
||||||
## Clear Responsibilities
|
## Clear Responsibilities
|
||||||
|
|
||||||
- [_Providers_](../providers/overview.md) discover the services that live on your infrastructure (their IP, health, ...)
|
- [_Providers_](../providers/overview.md) discover the services that live on your infrastructure (their IP, health, ...)
|
||||||
- [_Entrypoints_](./entrypoints.md) listen for incomming traffic (ports, SSL, ...)
|
- [_Entrypoints_](./entrypoints.md) listen for incomming traffic (ports, ...)
|
||||||
- [_Routers_](./routers.md) analyse the requests (host, path, headers, ...)
|
- [_Routers_](./routers/index.md) analyse the requests (host, path, headers, SSL, ...)
|
||||||
- [_Services_](./services.md) forward the request to your services (load balancing, ...)
|
- [_Services_](./services/index.md) forward the request to your services (load balancing, ...)
|
||||||
- [_Middlewares_](../middlewares/overview.md) may update the request or make decisions based on the request (authentication, rate limiting, headers, ...)
|
- [_Middlewares_](../middlewares/overview.md) may update the request or make decisions based on the request (authentication, rate limiting, headers, ...)
|
||||||
|
|
||||||
## Example with a File Provider
|
## Example with a File Provider
|
||||||
|
|
||||||
Below is an example of a full configuration file for the [file provider](../providers/file.md) that forwards `http://domain/whoami/` requests to a service reachable on `http://private/whoami-service/`.
|
Below is an example of a full configuration file for the [file provider](../providers/file.md) that forwards `http://domain/whoami/` requests to a service reachable on `http://private/whoami-service/`.
|
||||||
In the process, Traefik will make sure that the user is authenticated (using the [BasicAuth middleware](../middlewares/basicauth.md)).
|
In the process, Traefik will make sure that the user is authenticated (using the [BasicAuth middleware](../middlewares/basicauth.md)).
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[EntryPoints]
|
[entrypoints]
|
||||||
[EntryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8081" # Listen on port 8081 for incoming requests
|
address = ":8081" # Listen on port 8081 for incoming requests
|
||||||
|
|
||||||
[Providers]
|
[providers]
|
||||||
# Enable the file provider to define routers / middlewares / services in a file
|
[providers.file] # Enable the file provider to define routers / middlewares / services in a file
|
||||||
[Providers.file]
|
|
||||||
|
|
||||||
[Routers]
|
[http] # http routing section
|
||||||
[Routers.to-whoami] # Define a connection between requests and services
|
[http.routers]
|
||||||
rule = "Host(domain) && PathPrefix(/whoami/)"
|
[http.routers.to-whoami] # Define a connection between requests and services
|
||||||
middlewares = ["test-user"] # If the rule matches, applies the middleware
|
rule = "Host(domain) && PathPrefix(/whoami/)"
|
||||||
service = "whoami" # If the rule matches, forward to the whoami service (declared below)
|
middlewares = ["test-user"] # If the rule matches, applies the middleware
|
||||||
|
service = "whoami" # If the rule matches, forward to the whoami service (declared below)
|
||||||
[Middlewares]
|
|
||||||
[Middlewares.test-user.basicauth] # Define an authentication mechanism
|
[http.middlewares]
|
||||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
[http.middlewares.test-user.basicauth] # Define an authentication mechanism
|
||||||
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
||||||
[Services]
|
|
||||||
[Services.whoami.loadbalancer] # Define how to reach an existing service on our infrastructure
|
[http.services]
|
||||||
[[Services.whoami.loadbalancer.servers]]
|
[http.services.whoami.loadbalancer] # Define how to reach an existing service on our infrastructure
|
||||||
url = "http://private/whoami-service"
|
[[http.services.whoami.loadbalancer.servers]]
|
||||||
|
url = "http://private/whoami-service"
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note "The File Provider"
|
!!! note "The File Provider"
|
||||||
|
|
||||||
In this example, we use the [file provider](../providers/file.md).
|
In this example, we use the [file provider](../providers/file.md).
|
||||||
Even if it is one of the least magical way of configuring Traefik, it explicitly describes every available notion.
|
Even if it is one of the least magical way of configuring Traefik, it explicitly describes every available notion.
|
||||||
|
|
||||||
|
!!! note "HTTP / TCP"
|
||||||
|
|
||||||
|
In this example, we've defined routing rules for http requests only.
|
||||||
|
Traefik also supports TCP requests. To add [TCP routers](./routers/index.md) and [TCP services](./services/index.md), declare them in a TCP section like in the following.
|
||||||
|
|
||||||
|
??? example "Adding a TCP route for TLS requests on whoami.traefik.io"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
address = ":8081" # Listen on port 8081 for incoming requests
|
||||||
|
|
||||||
|
[providers]
|
||||||
|
[providers.file] # Enable the file provider to define routers / middlewares / services in a file
|
||||||
|
|
||||||
|
[http] # http routing section
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.to-whoami] # Define a connection between requests and services
|
||||||
|
rule = "Host(`domain`) && PathPrefix(/whoami/)"
|
||||||
|
middlewares = ["test-user"] # If the rule matches, applies the middleware
|
||||||
|
service = "whoami" # If the rule matches, forward to the whoami service (declared below)
|
||||||
|
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-user.basicauth] # Define an authentication mechanism
|
||||||
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"]
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.whoami.loadbalancer] # Define how to reach an existing service on our infrastructure
|
||||||
|
[[http.services.whoami.loadbalancer.servers]]
|
||||||
|
url = "http://private/whoami-service"
|
||||||
|
|
||||||
|
[tcp]
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.to-whoami-tcp]
|
||||||
|
rule = "HostSNI(`whoami-tcp.traefik.io`)"
|
||||||
|
service = "whoami-tcp"
|
||||||
|
[tcp.routers.to-whoami-tcp.tls]
|
||||||
|
|
||||||
|
[tcp.services]
|
||||||
|
[tcp.services.whoami-tcp.loadbalancer]
|
||||||
|
[[tcp.services.whoami-tcp.loadbalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
```
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
# Routers
|
|
||||||
|
|
||||||
Connecting Requests to Services
|
|
||||||
{: .subtitle }
|
|
||||||
|
|
||||||
![Routers](../assets/img/routers.png)
|
|
||||||
|
|
||||||
A router is in charge of connecting incoming requests to the services that can handle them.
|
|
||||||
In the process, routers may use pieces of [middleware](../middlewares/overview.md) to update the request, or act before forwarding the request to the service.
|
|
||||||
|
|
||||||
## Configuration Example
|
|
||||||
|
|
||||||
??? example "Requests /foo are Handled by service-foo -- Using the [File Provider](../providers/file.md)"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[Routers]
|
|
||||||
[Routers.my-router]
|
|
||||||
rule = "Path(/foo)"
|
|
||||||
service = "service-foo"
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "With a [Middleware](../middlewares/overview.md) -- using the [File Provider](../providers/file.md)"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[Routers]
|
|
||||||
[Routers.my-router]
|
|
||||||
rule = "Path(/foo)"
|
|
||||||
middlewares = ["authentication"] # declared elsewhere
|
|
||||||
service = "service-foo"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### EntryPoints
|
|
||||||
|
|
||||||
If not specified, routers will accept requests from all defined entrypoints.
|
|
||||||
If you want to limit the router scope to a set of entrypoint, set the entrypoints option.
|
|
||||||
|
|
||||||
??? example "Listens to Every EntryPoint"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[EntryPoints]
|
|
||||||
[EntryPoint.http]
|
|
||||||
# ...
|
|
||||||
[EntryPoint.https]
|
|
||||||
# ...
|
|
||||||
[EntryPoint.other]
|
|
||||||
# ...
|
|
||||||
|
|
||||||
[Routers]
|
|
||||||
[Routers.Router-1]
|
|
||||||
# By default, routers listen to every entrypoints
|
|
||||||
rule = "Host(traefik.io)"
|
|
||||||
service = "service-1"
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "Listens to Specific EntryPoints"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[EntryPoints]
|
|
||||||
[EntryPoint.http]
|
|
||||||
# ...
|
|
||||||
[EntryPoint.https]
|
|
||||||
# ...
|
|
||||||
[EntryPoint.other]
|
|
||||||
# ...
|
|
||||||
|
|
||||||
[Routers]
|
|
||||||
[Routers.Router-1]
|
|
||||||
entryPoints = ["https", "other"] # won't listen to entrypoint http
|
|
||||||
rule = "Host(traefik.io)"
|
|
||||||
service = "service-1"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rule
|
|
||||||
|
|
||||||
Rules are a set of matchers that determine if a particular request matches specific criteria.
|
|
||||||
If the rule is verified, then the router becomes active and calls middlewares, then forward the request to the service.
|
|
||||||
|
|
||||||
??? example "Host is traefik.io"
|
|
||||||
|
|
||||||
```
|
|
||||||
rule = "Host(`traefik.io`)"
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "Host is traefik.io OR Host is containo.us AND path is /traefik"
|
|
||||||
|
|
||||||
```
|
|
||||||
rule = "Host(`traefik.io`) || (Host(`containo.us`) && Path(`/traefik`))"
|
|
||||||
```
|
|
||||||
The table below lists all the available matchers:
|
|
||||||
|
|
||||||
| Rule | Description |
|
|
||||||
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
|
||||||
| ``Headers(`key`, `value`)`` | Check if there is a key `key`defined in the headers, with the value `value` |
|
|
||||||
| ``HeadersRegexp(`key`, `regexp`)`` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
|
|
||||||
| ``Host(`domain-1`, ...)`` | Check if the request domain targets one of the given `domains`. |
|
|
||||||
| ``HostRegexp(`traefik.io`, `{subdomain:[a-z]+}.traefik.io`, ...)`` | Check if the request domain matches the given `regexp`. |
|
|
||||||
| `Method(methods, ...)` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
|
|
||||||
| ``Path(`path`, `/articles/{category}/{id:[0-9]+}`, ...)`` | Match exact request path. It accepts a sequence of literal and regular expression paths. |
|
|
||||||
| ``PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`)`` | Match request prefix path. It accepts a sequence of literal and regular expression prefix paths. |
|
|
||||||
| ``Query(`foo=bar`, `bar=baz`)`` | Match` Query String parameters. It accepts a sequence of key=value pairs. |
|
|
||||||
|
|
||||||
!!! important "Regexp Syntax"
|
|
||||||
|
|
||||||
In order to use regular expressions with `Host` and `Path` expressions,
|
|
||||||
you must declare an arbitrarily named variable followed by the colon-separated regular expression, all enclosed in curly braces.
|
|
||||||
Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used (example: `/posts/{id:[0-9]+}`).
|
|
||||||
|
|
||||||
!!! tip "Combining Matchers Using Operators and Parenthesis"
|
|
||||||
|
|
||||||
You can combine multiple matchers using the AND (`&&`) and OR (`||) operators. You can also use parenthesis.
|
|
||||||
|
|
||||||
!!! important "Rule, Middleware, and Services"
|
|
||||||
|
|
||||||
The rule is evaluated "before" any middleware has the opportunity to work, and "before" the request is forwarded to the service.
|
|
||||||
|
|
||||||
!!! tip "Path Vs PathPrefix"
|
|
||||||
|
|
||||||
Use `Path` if your service listens on the exact path only. For instance, `Path: /products` would match `/products` but not `/products/shoes`.
|
|
||||||
|
|
||||||
Use a `*Prefix*` matcher if your service listens on a particular base path but also serves requests on sub-paths.
|
|
||||||
For instance, `PathPrefix: /products` would match `/products` but also `/products/shoes` and `/products/shirts`.
|
|
||||||
Since the path is forwarded as-is, your service is expected to listen on `/products`.
|
|
||||||
|
|
||||||
### Middlewares
|
|
||||||
|
|
||||||
You can attach a list of [middlewares](../middlewares/overview.md) to the routers.
|
|
||||||
The middlewares will take effect only if the rule matches, and before forwarding the request to the service.
|
|
||||||
|
|
||||||
### Service
|
|
||||||
|
|
||||||
You must attach a [service](./services.md) per router.
|
|
||||||
Services are the target for the router.
|
|
4
docs/content/routing/routers/.markdownlint.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"extends": "../../../.markdownlint.json",
|
||||||
|
"MD024": false
|
||||||
|
}
|
298
docs/content/routing/routers/index.md
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
# Routers
|
||||||
|
|
||||||
|
Connecting Requests to Services
|
||||||
|
{: .subtitle }
|
||||||
|
|
||||||
|
![routers](../../assets/img/routers.png)
|
||||||
|
|
||||||
|
A router is in charge of connecting incoming requests to the services that can handle them.
|
||||||
|
In the process, routers may use pieces of [middleware](../../middlewares/overview.md) to update the request, or act before forwarding the request to the service.
|
||||||
|
|
||||||
|
## Configuration Example
|
||||||
|
|
||||||
|
??? example "Requests /foo are Handled by service-foo -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.my-router]
|
||||||
|
rule = "Path(/foo)"
|
||||||
|
service = "service-foo"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "With a [middleware](../../middlewares/overview.md) -- using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.my-router]
|
||||||
|
rule = "Path(/foo)"
|
||||||
|
middlewares = ["authentication"] # declared elsewhere
|
||||||
|
service = "service-foo"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Forwarding all (non-tls) requests on port 3306 to a database service"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.mysql-default]
|
||||||
|
address = ":80"
|
||||||
|
[entrypoints.mysql-default]
|
||||||
|
address = ":3306"
|
||||||
|
|
||||||
|
[tcp]
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.to-database]
|
||||||
|
entrypoints = ["mysql-default"]
|
||||||
|
rule = "HostSNI(`*`)" # Catch every request (only available rule for non-tls routers. See below.)
|
||||||
|
service = "database"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring HTTP Routers
|
||||||
|
|
||||||
|
### EntryPoints
|
||||||
|
|
||||||
|
If not specified, HTTP routers will accept requests from all defined entrypoints.
|
||||||
|
If you want to limit the router scope to a set of entrypoint, set the entrypoints option.
|
||||||
|
|
||||||
|
??? example "Listens to Every EntryPoint"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
# ...
|
||||||
|
[entrypoints.web-secure]
|
||||||
|
# ...
|
||||||
|
[entrypoints.other]
|
||||||
|
# ...
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-1]
|
||||||
|
# By default, routers listen to every entrypoints
|
||||||
|
rule = "Host(traefik.io)"
|
||||||
|
service = "service-1"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Listens to Specific EntryPoints"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
# ...
|
||||||
|
[entrypoint.web-secure]
|
||||||
|
# ...
|
||||||
|
[entrypoint.other]
|
||||||
|
# ...
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-1]
|
||||||
|
entryPoints = ["web-secure", "other"] # won't listen to entrypoint web
|
||||||
|
rule = "Host(traefik.io)"
|
||||||
|
service = "service-1"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rule
|
||||||
|
|
||||||
|
Rules are a set of matchers that determine if a particular request matches specific criteria.
|
||||||
|
If the rule is verified, then the router becomes active and calls middlewares, then forward the request to the service.
|
||||||
|
|
||||||
|
??? example "Host is traefik.io"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
rule = "Host(`traefik.io`)"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Host is traefik.io OR Host is containo.us AND path is /traefik"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
rule = "Host(`traefik.io`) || (Host(`containo.us`) && Path(`/traefik`))"
|
||||||
|
```
|
||||||
|
The table below lists all the available matchers:
|
||||||
|
|
||||||
|
| Rule | Description |
|
||||||
|
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
||||||
|
| ``Headers(`key`, `value`)`` | Check if there is a key `key`defined in the headers, with the value `value` |
|
||||||
|
| ``HeadersRegexp(`key`, `regexp`)`` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
|
||||||
|
| ``Host(`domain-1`, ...)`` | Check if the request domain targets one of the given `domains`. |
|
||||||
|
| ``HostRegexp(`traefik.io`, `{subdomain:[a-z]+}.traefik.io`, ...)`` | Check if the request domain matches the given `regexp`. |
|
||||||
|
| `Method(methods, ...)` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
|
||||||
|
| ``Path(`path`, `/articles/{category}/{id:[0-9]+}`, ...)`` | Match exact request path. It accepts a sequence of literal and regular expression paths. |
|
||||||
|
| ``PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`)`` | Match request prefix path. It accepts a sequence of literal and regular expression prefix paths. |
|
||||||
|
| ``Query(`foo=bar`, `bar=baz`)`` | Match` Query String parameters. It accepts a sequence of key=value pairs. |
|
||||||
|
|
||||||
|
!!! important "Regexp Syntax"
|
||||||
|
|
||||||
|
In order to use regular expressions with `Host` and `Path` expressions,
|
||||||
|
you must declare an arbitrarily named variable followed by the colon-separated regular expression, all enclosed in curly braces.
|
||||||
|
Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used (example: `/posts/{id:[0-9]+}`).
|
||||||
|
|
||||||
|
!!! tip "Combining Matchers Using Operators and Parenthesis"
|
||||||
|
|
||||||
|
You can combine multiple matchers using the AND (`&&`) and OR (`||) operators. You can also use parenthesis.
|
||||||
|
|
||||||
|
!!! important "Rule, Middleware, and Services"
|
||||||
|
|
||||||
|
The rule is evaluated "before" any middleware has the opportunity to work, and "before" the request is forwarded to the service.
|
||||||
|
|
||||||
|
!!! tip "Path Vs PathPrefix"
|
||||||
|
|
||||||
|
Use `Path` if your service listens on the exact path only. For instance, `Path: /products` would match `/products` but not `/products/shoes`.
|
||||||
|
|
||||||
|
Use a `*Prefix*` matcher if your service listens on a particular base path but also serves requests on sub-paths.
|
||||||
|
For instance, `PathPrefix: /products` would match `/products` but also `/products/shoes` and `/products/shirts`.
|
||||||
|
Since the path is forwarded as-is, your service is expected to listen on `/products`.
|
||||||
|
|
||||||
|
### Middlewares
|
||||||
|
|
||||||
|
You can attach a list of [middlewares](../../middlewares/overview.md) to each HTTP router.
|
||||||
|
The middlewares will take effect only if the rule matches, and before forwarding the request to the service.
|
||||||
|
|
||||||
|
### Service
|
||||||
|
|
||||||
|
You must attach a [service](../services/index.md) per router.
|
||||||
|
Services are the target for the router.
|
||||||
|
|
||||||
|
!!! note "HTTP Only"
|
||||||
|
|
||||||
|
HTTP routers can only target HTTP services (not TCP services).
|
||||||
|
|
||||||
|
### TLS
|
||||||
|
|
||||||
|
When specifying a TLS section, you tell Traefik that the current router is dedicated to HTTPS requests only (and that the router should ignore HTTP (non tls) requests).
|
||||||
|
Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services).
|
||||||
|
|
||||||
|
??? example "Configuring the router to accept HTTPS requests only"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-1]
|
||||||
|
rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
|
||||||
|
service = "service-id"
|
||||||
|
[http.routers.Router-1.tls] # will terminate the TLS request
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note "HTTPS & ACME"
|
||||||
|
|
||||||
|
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
||||||
|
In the near future, options will be available to enable fine-grain control of the TLS parameters.
|
||||||
|
|
||||||
|
!!! note "Passthrough"
|
||||||
|
|
||||||
|
On TCP routers, you can configure a passthrough option so that Traefik doesn't terminate the TLS connection.
|
||||||
|
|
||||||
|
!!! important "Routers for HTTP & HTTPS"
|
||||||
|
|
||||||
|
If you need to define the same route for both HTTP and HTTPS requests, you will need to define two different routers: one with the tls section, one without.
|
||||||
|
|
||||||
|
??? example "HTTP & HTTPS routes"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-1-https]
|
||||||
|
rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
|
||||||
|
service = "service-id"
|
||||||
|
[http.routers.Router-1.tls] # will terminate the TLS request
|
||||||
|
|
||||||
|
[http.routers.Router-1-http]
|
||||||
|
rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
|
||||||
|
service = "service-id"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring TCP Routers
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
If both HTTP routers and TCP routers listen to the same entrypoints, the TCP routers will apply *before* the HTTP routers.
|
||||||
|
If no matching route is found for the TCP routers, then the HTTP routers will take over.
|
||||||
|
|
||||||
|
### EntryPoints
|
||||||
|
|
||||||
|
If not specified, TCP routers will accept requests from all defined entrypoints.
|
||||||
|
If you want to limit the router scope to a set of entrypoints, set the entrypoints option.
|
||||||
|
|
||||||
|
??? example "Listens to Every EntryPoint"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
# ...
|
||||||
|
[entrypoints.web-secure]
|
||||||
|
# ...
|
||||||
|
[entrypoints.other]
|
||||||
|
# ...
|
||||||
|
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-1]
|
||||||
|
# By default, routers listen to every entrypoints
|
||||||
|
rule = "Host(traefik.io)"
|
||||||
|
service = "service-1"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Listens to Specific EntryPoints"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
# ...
|
||||||
|
[entrypoint.web-secure]
|
||||||
|
# ...
|
||||||
|
[entrypoint.other]
|
||||||
|
# ...
|
||||||
|
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-1]
|
||||||
|
entryPoints = ["web-secure", "other"] # won't listen to entrypoint web
|
||||||
|
rule = "Host(traefik.io)"
|
||||||
|
service = "service-1"
|
||||||
|
[tcp.routers.Router-1.tls] # will route TLS requests (and ignore non tls requests)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rule
|
||||||
|
|
||||||
|
| Rule | Description |
|
||||||
|
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
||||||
|
| ``HostSNI(`domain-1`, ...)`` | Check if the Server Name Indication corresponds to the given `domains`. |
|
||||||
|
|
||||||
|
!!! important "HostSNI & TLS"
|
||||||
|
|
||||||
|
It is important to note that the Server Name Indication is an extension of the TLS protocol.
|
||||||
|
Hence, only TLS routers will be able to specify a domain name with that rule.
|
||||||
|
However, non-TLS routers will have to explicitly use that rule with `*` (every domain) to state that every non-TLS request will be handled by the router.
|
||||||
|
|
||||||
|
### Services
|
||||||
|
|
||||||
|
You must attach a TCP [service](../services/index.md) per TCP router.
|
||||||
|
Services are the target for the router.
|
||||||
|
|
||||||
|
!!! note "TCP Only"
|
||||||
|
|
||||||
|
TCP routers can only target TCP services (not HTTP services).
|
||||||
|
|
||||||
|
### TLS
|
||||||
|
|
||||||
|
When specifying a TLS section, you tell Traefik that the current router is dedicated to TLS requests only (and that the router should ignore non-tls requests).
|
||||||
|
By default, Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services), but you can tell Traefik that the request should pass through (keeping the encrypted data) and be forwarded to the service "as is".
|
||||||
|
|
||||||
|
??? example "Configuring TLS Termination"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-1]
|
||||||
|
rule = "Host(`foo-domain`)"
|
||||||
|
service = "service-id"
|
||||||
|
[tcp.routers.Router-1.tls] # will terminate the TLS request by default
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Configuring passthrough"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-1]
|
||||||
|
rule = "Host(`foo-domain`)"
|
||||||
|
service = "service-id"
|
||||||
|
[tcp.routers.Router-1.tls]
|
||||||
|
passthrough=true
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note "TLS & ACME"
|
||||||
|
|
||||||
|
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
||||||
|
In the near future, options will be available to enable fine-grain control of the TLS parameters.
|
4
docs/content/routing/services/.markdownlint.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"extends": "../../../.markdownlint.json",
|
||||||
|
"MD024": false
|
||||||
|
}
|
|
@ -3,50 +3,61 @@
|
||||||
Configuring How to Reach the Services
|
Configuring How to Reach the Services
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
|
||||||
![Services](../assets/img/services.png)
|
![services](../../assets/img/services.png)
|
||||||
|
|
||||||
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
|
The `Services` are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
|
||||||
|
|
||||||
## Configuration Example
|
## Configuration Example
|
||||||
|
|
||||||
??? example "Declaring a Service with Two Servers (with Load Balancing) -- Using the [File Provider](../providers/file.md)"
|
??? example "Declaring an HTTP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service.LoadBalancer]
|
[http.services.my-service.LoadBalancer]
|
||||||
method = "wrr" # Load Balancing based on weights
|
method = "wrr" # Load Balancing based on weights
|
||||||
|
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
weight = 30 # 30% of the requests will go to that instance
|
weight = 30 # 30% of the requests will go to that instance
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-2/"
|
url = "http://private-ip-server-2/"
|
||||||
weight = 70 # 70% of the requests will go to that instance
|
weight = 70 # 70% of the requests will go to that instance
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
??? example "Declaring a TCP Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.services]
|
||||||
|
[tcp.services.my-service.LoadBalancer]
|
||||||
|
[[tcp.services.my-service.LoadBalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
[[tcp.services.my-service.LoadBalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring HTTP Services
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
|
||||||
Currently, the `LoadBalancer` service is the only supported kind of `Service` (see below).
|
Currently, `LoadBalancer` is the only supported kind of HTTP `Service` (see below).
|
||||||
However, since Traefik is an ever evolving project, other kind of Services will be available in the future,
|
However, since Traefik is an ever evolving project, other kind of HTTP Services will be available in the future,
|
||||||
reason why you have to specify what kind of service you declare.
|
reason why you have to specify it.
|
||||||
|
|
||||||
### Load Balancer
|
### Load Balancer
|
||||||
|
|
||||||
The `LoadBalancer` service is able to load balance the requests between multiple instances of your programs.
|
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||||
|
|
||||||
??? example "Declaring a Service with Two Servers (with Load Balancing) -- Using the [File Provider](../providers/file.md)"
|
??? example "Declaring a Service with Two Servers (with Load Balancing) -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service.LoadBalancer]
|
[http.services.my-service.LoadBalancer]
|
||||||
method = "wrr" # Load Balancing based on weights
|
method = "wrr" # Load Balancing based on weights
|
||||||
|
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
weight = 50 # 50% of the requests will go to that instance
|
weight = 50 # 50% of the requests will go to that instance
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-2/"
|
url = "http://private-ip-server-2/"
|
||||||
weight = 50 # 50% of the requests will go to that instance
|
weight = 50 # 50% of the requests will go to that instance
|
||||||
```
|
```
|
||||||
|
@ -60,14 +71,14 @@ The `weight` option defines the weight of the server for the load balancing algo
|
||||||
!!! note
|
!!! note
|
||||||
Paths in the servers' `url` have no effet.
|
Paths in the servers' `url` have no effet.
|
||||||
If you want the requests to be sent to a specific path on your servers,
|
If you want the requests to be sent to a specific path on your servers,
|
||||||
configure your [`routers`](./routers.md) to use a corresponding [Middleware](../middlewares/overview.md) (e.g. the [AddPrefix](../middlewares/addprefix.md) or [ReplacePath](../middlewares/replacepath.md)) middlewares.
|
configure your [`routers`](../routers/index.md) to use a corresponding [middleware](../../middlewares/overview.md) (e.g. the [AddPrefix](../../middlewares/addprefix.md) or [ReplacePath](../../middlewares/replacepath.md)) middlewares.
|
||||||
|
|
||||||
??? example "A Service with One Server -- Using the [File Provider](../providers/file.md)"
|
??? example "A Service with One Server -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service.LoadBalancer]
|
[http.services.my-service.LoadBalancer]
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -77,16 +88,16 @@ Various methods of load balancing are supported:
|
||||||
|
|
||||||
- `wrr`: Weighted Round Robin.
|
- `wrr`: Weighted Round Robin.
|
||||||
- `drr`: Dynamic Round Robin: increases weights on servers that perform better than others (rolls back to original weights when the server list is updated)
|
- `drr`: Dynamic Round Robin: increases weights on servers that perform better than others (rolls back to original weights when the server list is updated)
|
||||||
|
|
||||||
??? example "Load Balancing Using DRR -- Using the [File Provider](../providers/file.md)"
|
??? example "Load Balancing Using DRR -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service.LoadBalancer]
|
[http.services.my-service.LoadBalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
[[Services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -106,17 +117,17 @@ On subsequent requests, the client is forwarded to the same server.
|
||||||
??? example "Adding Stickiness"
|
??? example "Adding Stickiness"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service]
|
[http.services.my-service]
|
||||||
[Services.my-service.LoadBalancer.stickiness]
|
[http.services.my-service.LoadBalancer.stickiness]
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Adding Stickiness with a Custom Cookie Name"
|
??? example "Adding Stickiness with a Custom Cookie Name"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.my-service]
|
[http.services.my-service]
|
||||||
[Services.my-service.LoadBalancer.stickiness]
|
[http.services.my-service.LoadBalancer.stickiness]
|
||||||
cookieName = "my_stickiness_cookie_name"
|
cookieName = "my_stickiness_cookie_name"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -148,9 +159,9 @@ Below are the available options for the health check mechanism:
|
||||||
??? example "Custom Interval & Timeout -- Using the File Provider"
|
??? example "Custom Interval & Timeout -- Using the File Provider"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Servicess.Service-1]
|
[http.servicess.Service-1]
|
||||||
[Services.Service-1.healthcheck]
|
[http.services.Service-1.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
interval = "10s"
|
interval = "10s"
|
||||||
timeout = "3s"
|
timeout = "3s"
|
||||||
|
@ -159,9 +170,9 @@ Below are the available options for the health check mechanism:
|
||||||
??? example "Custom Port -- Using the File Provider"
|
??? example "Custom Port -- Using the File Provider"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.Service-1]
|
[http.services.Service-1]
|
||||||
[Services.Service-1.healthcheck]
|
[http.services.Service-1.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
port = 8080
|
port = 8080
|
||||||
```
|
```
|
||||||
|
@ -169,9 +180,9 @@ Below are the available options for the health check mechanism:
|
||||||
??? example "Custom Scheme -- Using the File Provider"
|
??? example "Custom Scheme -- Using the File Provider"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.Service-1]
|
[http.services.Service-1]
|
||||||
[Services.Service-1.healthcheck]
|
[http.services.Service-1.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
scheme = "http"
|
scheme = "http"
|
||||||
```
|
```
|
||||||
|
@ -179,12 +190,53 @@ Below are the available options for the health check mechanism:
|
||||||
??? example "Additional HTTP Headers -- Using the File Provider"
|
??? example "Additional HTTP Headers -- Using the File Provider"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.Service-1]
|
[http.services.Service-1]
|
||||||
[Servicess.Service-1.healthcheck]
|
[http.servicess.Service-1.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
|
|
||||||
[Service.Service-1.healthcheck.headers]
|
[Service.Service-1.healthcheck.headers]
|
||||||
My-Custom-Header = "foo"
|
My-Custom-Header = "foo"
|
||||||
My-Header = "bar"
|
My-Header = "bar"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Configuring TCP Services
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
Currently, `LoadBalancer` is the only supported kind of TCP `Service`.
|
||||||
|
However, since Traefik is an ever evolving project, other kind of TCP Services will be available in the future,
|
||||||
|
reason why you have to specify it.
|
||||||
|
|
||||||
|
### Load Balancer
|
||||||
|
|
||||||
|
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||||
|
|
||||||
|
??? example "Declaring a Service with Two Servers -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.services]
|
||||||
|
[tcp.services.my-service.LoadBalancer]
|
||||||
|
[[tcp.services.my-service.LoadBalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
[[tcp.services.my-service.LoadBalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Servers
|
||||||
|
|
||||||
|
Servers declare a single instance of your program.
|
||||||
|
The `address` option (IP:Port) point to a specific instance.
|
||||||
|
|
||||||
|
??? example "A Service with One Server -- Using the [File Provider](../../providers/file.md)"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.services]
|
||||||
|
[tcp.services.my-service.LoadBalancer]
|
||||||
|
[[tcp.services.my-service.LoadBalancer.servers]]
|
||||||
|
address = "xx.xx.xx.xx:xx"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note "Weight"
|
||||||
|
|
||||||
|
The TCP LoadBalancer is currently a round robin only implementation and doesn't yet support weights.
|
|
@ -79,9 +79,11 @@ nav:
|
||||||
- 'Routing & Load Balancing':
|
- 'Routing & Load Balancing':
|
||||||
- 'Overview': 'routing/overview.md'
|
- 'Overview': 'routing/overview.md'
|
||||||
- 'Entrypoints': 'routing/entrypoints.md'
|
- 'Entrypoints': 'routing/entrypoints.md'
|
||||||
- 'Routers': 'routing/routers.md'
|
- 'Routers': 'routing/routers/index.md'
|
||||||
- 'Services': 'routing/services.md'
|
- 'Services': 'routing/services/index.md'
|
||||||
- 'ACME': 'routing/acme.md'
|
- 'HTTPS & TLS':
|
||||||
|
- 'Overview': 'https-tls/overview.md'
|
||||||
|
- 'ACME': 'https-tls/acme.md'
|
||||||
- 'Middlewares':
|
- 'Middlewares':
|
||||||
- 'Overview': 'middlewares/overview.md'
|
- 'Overview': 'middlewares/overview.md'
|
||||||
- 'AddPrefix': 'middlewares/addprefix.md'
|
- 'AddPrefix': 'middlewares/addprefix.md'
|
||||||
|
|
|
@ -11,6 +11,19 @@ readonly BASE_DIR=/app
|
||||||
echo "== Linting Markdown"
|
echo "== Linting Markdown"
|
||||||
# Uses the file ".markdownlint.json" for setup
|
# Uses the file ".markdownlint.json" for setup
|
||||||
cd "${BASE_DIR}" || exit 1
|
cd "${BASE_DIR}" || exit 1
|
||||||
markdownlint --config ${BASE_DIR}/content/includes/.markdownlint.json "${BASE_DIR}/content/**/*.md" || EXIT_CODE=1
|
|
||||||
|
LINTER_EXCLUSIONS="$(find "${BASE_DIR}/content" -type f -name '.markdownlint.json')" \
|
||||||
|
GLOBAL_LINT_OPTIONS="--config ${BASE_DIR}/.markdownlint.json"
|
||||||
|
|
||||||
|
# Lint the specific folders (containing linter specific rulesets)
|
||||||
|
for LINTER_EXCLUSION in ${LINTER_EXCLUSIONS}
|
||||||
|
do
|
||||||
|
markdownlint --config "${LINTER_EXCLUSION}" "$(dirname "${LINTER_EXCLUSION}")" || EXIT_CODE=1
|
||||||
|
# Add folder to the ignore list for global lint
|
||||||
|
GLOBAL_LINT_OPTIONS="${GLOBAL_LINT_OPTIONS} --ignore=$(dirname "${LINTER_EXCLUSION}")"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Lint all the content, excluding the previously done`
|
||||||
|
eval markdownlint "${GLOBAL_LINT_OPTIONS}" "${BASE_DIR}/content/**/*.md" || EXIT_CODE=1
|
||||||
|
|
||||||
exit "${EXIT_CODE}"
|
exit "${EXIT_CODE}"
|
||||||
|
|
|
@ -5,8 +5,8 @@ traefikLogsFile = "log/traefik.log"
|
||||||
accessLogsFile = "log/access.log"
|
accessLogsFile = "log/access.log"
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":7888"
|
address = ":7888"
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -5,8 +5,8 @@ traefikLogsFile = "log/traefik.log"
|
||||||
accessLogsFile = "log/access.log"
|
accessLogsFile = "log/access.log"
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":7888"
|
address = ":7888"
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.http]
|
|
||||||
address = ":80"
|
address = ":80"
|
||||||
[entryPoints.http.redirect]
|
[entrypoints.web.redirect]
|
||||||
entryPoint = "https"
|
entryPoint = "https"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.http]
|
|
||||||
address = ":80"
|
address = ":80"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
|
|
|
@ -43,7 +43,7 @@ Edit your `docker-compose.yml` file and add the following at the end of your fil
|
||||||
whoami:
|
whoami:
|
||||||
image: containous/whoami # A container that exposes an API to show its IP address
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
labels:
|
labels:
|
||||||
- "traefik.router.rule=Host:whoami.docker.localhost"
|
- "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 simple web service that outputs information about the machine it is deployed on (its IP address, host, and so on).
|
||||||
|
|
|
@ -15,4 +15,4 @@ services:
|
||||||
whoami:
|
whoami:
|
||||||
image: containous/whoami # A container that exposes an API to show its IP address
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
labels:
|
labels:
|
||||||
- "traefik.router.rule=Host:whoami.docker.localhost"
|
- "traefik.http.routers.whoami.rule=Host:whoami.docker.localhost"
|
||||||
|
|
|
@ -121,11 +121,12 @@ func (s *AcmeSuite) TearDownSuite(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01DomainsAtStart(c *check.C) {
|
func (s *AcmeSuite) TestHTTP01DomainsAtStart(c *check.C) {
|
||||||
|
c.Skip("We need to fix DefaultCertificate at start")
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
Domains: types.Domains{types.Domain{
|
Domains: types.Domains{types.Domain{
|
||||||
Main: "traefik.acme.wtf",
|
Main: "traefik.acme.wtf",
|
||||||
}},
|
}},
|
||||||
|
@ -139,11 +140,12 @@ func (s *AcmeSuite) TestHTTP01DomainsAtStart(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01DomainsInSANAtStart(c *check.C) {
|
func (s *AcmeSuite) TestHTTP01DomainsInSANAtStart(c *check.C) {
|
||||||
|
c.Skip("We need to fix DefaultCertificate at start")
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
Domains: types.Domains{types.Domain{
|
Domains: types.Domains{types.Domain{
|
||||||
Main: "acme.wtf",
|
Main: "acme.wtf",
|
||||||
SANs: []string{"traefik.acme.wtf"},
|
SANs: []string{"traefik.acme.wtf"},
|
||||||
|
@ -162,7 +164,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRule(c *check.C) {
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -178,7 +180,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA(c *check.C) {
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
KeyType: "EC384",
|
KeyType: "EC384",
|
||||||
},
|
},
|
||||||
|
@ -195,7 +197,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo(c *check.C) {
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
KeyType: "INVALID",
|
KeyType: "INVALID",
|
||||||
},
|
},
|
||||||
|
@ -207,28 +209,12 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo(c *check.C) {
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
s.retrieveAcmeCertificate(c, testCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnHostRuleWithPath(c *check.C) {
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_http01_web_path.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
|
||||||
OnHostRule: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: acmeDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnHostRuleStaticCertificatesWithWildcard(c *check.C) {
|
func (s *AcmeSuite) TestHTTP01OnHostRuleStaticCertificatesWithWildcard(c *check.C) {
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -244,7 +230,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls_dynamic.toml",
|
traefikConfFilePath: "fixtures/acme/acme_tls_dynamic.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -255,78 +241,6 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
s.retrieveAcmeCertificate(c, testCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnDemand(c *check.C) {
|
|
||||||
c.Skip("on demand")
|
|
||||||
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
|
||||||
OnDemand: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: acmeDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcard(c *check.C) {
|
|
||||||
c.Skip("on demand")
|
|
||||||
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
|
||||||
OnDemand: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: wildcardDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcardMultipleEntrypoints(c *check.C) {
|
|
||||||
c.Skip("on demand")
|
|
||||||
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls_multiple_entrypoints.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
|
||||||
OnDemand: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: acmeDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestHTTP01OnDemandDynamicCertificatesWithWildcard(c *check.C) {
|
|
||||||
c.Skip("on demand")
|
|
||||||
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls_dynamic.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
|
||||||
OnDemand: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: wildcardDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
|
func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
|
@ -343,23 +257,8 @@ func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
s.retrieveAcmeCertificate(c, testCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestTLSALPN01OnDemand(c *check.C) {
|
|
||||||
testCase := acmeTestCase{
|
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
|
||||||
template: templateModel{
|
|
||||||
Acme: acme.Configuration{
|
|
||||||
TLSChallenge: &acme.TLSChallenge{},
|
|
||||||
OnDemand: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedCommonName: acmeDomain,
|
|
||||||
expectedAlgorithm: x509.RSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.retrieveAcmeCertificate(c, testCase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AcmeSuite) TestTLSALPN01DomainsAtStart(c *check.C) {
|
func (s *AcmeSuite) TestTLSALPN01DomainsAtStart(c *check.C) {
|
||||||
|
c.Skip("We need to fix DefaultCertificate at start")
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
|
@ -378,6 +277,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsAtStart(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestTLSALPN01DomainsInSANAtStart(c *check.C) {
|
func (s *AcmeSuite) TestTLSALPN01DomainsInSANAtStart(c *check.C) {
|
||||||
|
c.Skip("We need to fix DefaultCertificate at start")
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
|
@ -397,6 +297,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSANAtStart(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AcmeSuite) TestTLSALPN01DomainsWithProvidedWildcardDomainAtStart(c *check.C) {
|
func (s *AcmeSuite) TestTLSALPN01DomainsWithProvidedWildcardDomainAtStart(c *check.C) {
|
||||||
|
c.Skip("We need to fix DefaultCertificate at start")
|
||||||
testCase := acmeTestCase{
|
testCase := acmeTestCase{
|
||||||
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
||||||
template: templateModel{
|
template: templateModel{
|
||||||
|
@ -419,7 +320,7 @@ func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||||
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
|
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
|
||||||
Acme: acme.Configuration{
|
Acme: acme.Configuration{
|
||||||
CAServer: "http://wrongurl:4001/directory",
|
CAServer: "http://wrongurl:4001/directory",
|
||||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "web"},
|
||||||
OnHostRule: true,
|
OnHostRule: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"github.com/abronan/valkeyrie/store"
|
"github.com/abronan/valkeyrie/store"
|
||||||
"github.com/abronan/valkeyrie/store/consul"
|
"github.com/abronan/valkeyrie/store/consul"
|
||||||
"github.com/containous/staert"
|
"github.com/containous/staert"
|
||||||
"github.com/containous/traefik/cluster"
|
|
||||||
"github.com/containous/traefik/integration/try"
|
"github.com/containous/traefik/integration/try"
|
||||||
|
"github.com/containous/traefik/old/cluster"
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
checker "github.com/vdemeester/shakers"
|
checker "github.com/vdemeester/shakers"
|
||||||
)
|
)
|
||||||
|
|
|
@ -158,13 +158,13 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
|
||||||
|
|
||||||
// Start a container with some labels
|
// Start a container with some labels
|
||||||
labels := map[string]string{
|
labels := map[string]string{
|
||||||
"traefik.Routers.Super.Rule": "Host(`my.super.host`)",
|
"traefik.http.Routers.Super.Rule": "Host(`my.super.host`)",
|
||||||
}
|
}
|
||||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||||
|
|
||||||
// Start another container by replacing a '.' by a '-'
|
// Start another container by replacing a '.' by a '-'
|
||||||
labels = map[string]string{
|
labels = map[string]string{
|
||||||
"traefik.Routers.SuperHost.Rule": "Host(`my-super.host`)",
|
"traefik.http.Routers.SuperHost.Rule": "Host(`my-super.host`)",
|
||||||
}
|
}
|
||||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blablabla")
|
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blablabla")
|
||||||
|
|
||||||
|
@ -250,8 +250,8 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
|
||||||
|
|
||||||
// Start a container with some labels
|
// Start a container with some labels
|
||||||
labels := map[string]string{
|
labels := map[string]string{
|
||||||
"traefik.Routers.Super.Rule": "Host(`my.super.host`)",
|
"traefik.http.Routers.Super.Rule": "Host(`my.super.host`)",
|
||||||
"traefik.Services.powpow.LoadBalancer.server.Port": "2375",
|
"traefik.http.Services.powpow.LoadBalancer.server.Port": "2375",
|
||||||
}
|
}
|
||||||
s.startContainerWithNameAndLabels(c, "powpow", "swarm:1.0.0", labels, "manage", "token://blabla")
|
s.startContainerWithNameAndLabels(c, "powpow", "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@ checkNewVersion = false
|
||||||
[accessLog]
|
[accessLog]
|
||||||
filePath = "access.log"
|
filePath = "access.log"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.frontendRedirect]
|
[entrypoints.frontendRedirect]
|
||||||
address = ":8005"
|
address = ":8005"
|
||||||
[entryPoints.httpFrontendAuth]
|
[entrypoints.httpFrontendAuth]
|
||||||
address = ":8006"
|
address = ":8006"
|
||||||
[entryPoints.httpRateLimit]
|
[entrypoints.httpRateLimit]
|
||||||
address = ":8007"
|
address = ":8007"
|
||||||
[entryPoints.digestAuth]
|
[entrypoints.digestAuth]
|
||||||
address = ":8008"
|
address = ":8008"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
[entryPoints]
|
address = "{{ .PortHTTP }}"
|
||||||
[entryPoints.http]
|
[entrypoints.web-secure]
|
||||||
address = "{{ .PortHTTP }}"
|
address = "{{ .PortHTTPS }}"
|
||||||
[entryPoints.https]
|
|
||||||
address = "{{ .PortHTTPS }}"
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
storage = "/tmp/acme.json"
|
storage = "/tmp/acme.json"
|
||||||
entryPoint = "https"
|
# entryPoint = "https"
|
||||||
acmeLogging = true
|
acmeLogging = true
|
||||||
onDemand = {{ .Acme.OnDemand }}
|
|
||||||
onHostRule = {{ .Acme.OnHostRule }}
|
onHostRule = {{ .Acme.OnHostRule }}
|
||||||
keyType = "{{ .Acme.KeyType }}"
|
keyType = "{{ .Acme.KeyType }}"
|
||||||
caServer = "{{ .Acme.CAServer }}"
|
caServer = "{{ .Acme.CAServer }}"
|
||||||
|
@ -42,14 +38,15 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.test.loadbalancer]
|
[http.services.test.loadbalancer]
|
||||||
[[services.test.loadbalancer.servers]]
|
[[http.services.test.loadbalancer.servers]]
|
||||||
url = "http://127.0.0.1:9010"
|
url = "http://127.0.0.1:9010"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.test]
|
[http.routers.test]
|
||||||
service = "test"
|
entryPoints = ["web-secure"]
|
||||||
rule = "Host(`traefik.acme.wtf`)"
|
rule = "Host(`traefik.acme.wtf`)"
|
||||||
entryPoints = ["https"]
|
service = "test"
|
||||||
|
[http.routers.test.tls]
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
[log]
|
|
||||||
logLevel = "DEBUG"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.http]
|
|
||||||
address = "{{ .PortHTTP }}"
|
|
||||||
[entryPoints.https]
|
|
||||||
address = "{{ .PortHTTPS }}"
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
[acme]
|
|
||||||
email = "test@traefik.io"
|
|
||||||
storage = "/tmp/acme.json"
|
|
||||||
entryPoint = "https"
|
|
||||||
acmeLogging = true
|
|
||||||
onDemand = {{ .Acme.OnDemand }}
|
|
||||||
onHostRule = {{ .Acme.OnHostRule }}
|
|
||||||
keyType = "{{ .Acme.KeyType }}"
|
|
||||||
caServer = "{{ .Acme.CAServer }}"
|
|
||||||
|
|
||||||
{{if .Acme.HTTPChallenge }}
|
|
||||||
[acme.httpChallenge]
|
|
||||||
entryPoint = "{{ .Acme.HTTPChallenge.EntryPoint }}"
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{range .Acme.Domains}}
|
|
||||||
[[acme.domains]]
|
|
||||||
main = "{{ .Main }}"
|
|
||||||
sans = [{{range .SANs }}
|
|
||||||
"{{.}}",
|
|
||||||
{{end}}]
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
[web]
|
|
||||||
path="/traefik"
|
|
||||||
|
|
||||||
[providers]
|
|
||||||
[providers.file]
|
|
||||||
|
|
||||||
[services]
|
|
||||||
[services.test.loadbalancer]
|
|
||||||
[[services.test.loadbalancer.servers]]
|
|
||||||
url = "http://127.0.0.1:9010"
|
|
||||||
weight = 1
|
|
||||||
|
|
||||||
[routers]
|
|
||||||
[routers.test]
|
|
||||||
service = "test"
|
|
||||||
rule = "Host(`traefik.acme.wtf`)"
|
|
||||||
entryPoints = ["https"]
|
|
|
@ -1,22 +1,17 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = "{{ .PortHTTP }}"
|
address = "{{ .PortHTTP }}"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = "{{ .PortHTTPS }}"
|
address = "{{ .PortHTTPS }}"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
|
||||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
storage = "/tmp/acme.json"
|
storage = "/tmp/acme.json"
|
||||||
entryPoint = "https"
|
# entryPoint = "https"
|
||||||
acmeLogging = true
|
acmeLogging = true
|
||||||
onDemand = {{ .Acme.OnDemand }}
|
|
||||||
onHostRule = {{ .Acme.OnHostRule }}
|
onHostRule = {{ .Acme.OnHostRule }}
|
||||||
keyType = "{{ .Acme.KeyType }}"
|
keyType = "{{ .Acme.KeyType }}"
|
||||||
caServer = "{{ .Acme.CAServer }}"
|
caServer = "{{ .Acme.CAServer }}"
|
||||||
|
@ -43,14 +38,19 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.test.loadbalancer]
|
[http.services.test.loadbalancer]
|
||||||
[[services.test.loadbalancer.servers]]
|
[[http.services.test.loadbalancer.servers]]
|
||||||
url = "http://127.0.0.1:9010"
|
url = "http://127.0.0.1:9010"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.test]
|
[http.routers.test]
|
||||||
service = "test"
|
entryPoints = ["web-secure"]
|
||||||
rule = "Host(`traefik.acme.wtf`)"
|
rule = "Host(`traefik.acme.wtf`)"
|
||||||
entryPoints = ["https"]
|
service = "test"
|
||||||
|
[http.routers.test.tls]
|
||||||
|
|
||||||
|
[tlsStores.default.defaultCertificate]
|
||||||
|
certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||||
|
keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entrypoints]
|
||||||
[entryPoints]
|
[entrypoints.web]
|
||||||
[entryPoints.http]
|
|
||||||
address = "{{ .PortHTTP }}"
|
address = "{{ .PortHTTP }}"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = "{{ .PortHTTPS }}"
|
address = "{{ .PortHTTPS }}"
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
storage = "/tmp/acme.json"
|
storage = "/tmp/acme.json"
|
||||||
entryPoint = "https"
|
# entryPoint = "https"
|
||||||
acmeLogging = true
|
acmeLogging = true
|
||||||
onDemand = {{ .Acme.OnDemand }}
|
|
||||||
onHostRule = {{ .Acme.OnHostRule }}
|
onHostRule = {{ .Acme.OnHostRule }}
|
||||||
keyType = "{{ .Acme.KeyType }}"
|
keyType = "{{ .Acme.KeyType }}"
|
||||||
caServer = "{{ .Acme.CAServer }}"
|
caServer = "{{ .Acme.CAServer }}"
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
|
address = "{{ .PortHTTP }}"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints.web-secure]
|
||||||
[entryPoints.http]
|
address = "{{ .PortHTTPS }}"
|
||||||
address = "{{ .PortHTTP }}"
|
|
||||||
[entryPoints.https]
|
[entrypoints.traefik]
|
||||||
address = "{{ .PortHTTPS }}"
|
address = ":9000"
|
||||||
[entryPoints.https.tls]
|
# FIXME
|
||||||
[entryPoints.traefik]
|
# [entrypoints.traefik.tls]
|
||||||
address = ":9000"
|
# [entrypoints.traefik.tls.DefaultCertificate]
|
||||||
[entryPoints.traefik.tls]
|
# certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||||
[entryPoints.traefik.tls.DefaultCertificate]
|
# keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
|
||||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
|
||||||
|
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
storage = "/tmp/acme.json"
|
storage = "/tmp/acme.json"
|
||||||
entryPoint = "https"
|
# entryPoint = "https"
|
||||||
acmeLogging = true
|
acmeLogging = true
|
||||||
onDemand = {{ .Acme.OnDemand }}
|
|
||||||
onHostRule = {{ .Acme.OnHostRule }}
|
onHostRule = {{ .Acme.OnHostRule }}
|
||||||
keyType = "{{ .Acme.KeyType }}"
|
keyType = "{{ .Acme.KeyType }}"
|
||||||
caServer = "{{ .Acme.CAServer }}"
|
caServer = "{{ .Acme.CAServer }}"
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
[services]
|
[http.services]
|
||||||
[services.test.loadbalancer]
|
[http.services.test.loadbalancer]
|
||||||
[[services.test.loadbalancer.servers]]
|
[[http.services.test.loadbalancer.servers]]
|
||||||
url = "http://127.0.0.1:9010"
|
url = "http://127.0.0.1:9010"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[routers]
|
|
||||||
[routers.test]
|
|
||||||
service = "test"
|
|
||||||
rule = "Host(`traefik.acme.wtf`)"
|
|
||||||
entryPoints = ["https"]
|
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.test]
|
||||||
|
entryPoints = ["web-secure"]
|
||||||
|
rule = "Host(`traefik.acme.wtf`)"
|
||||||
|
service = "test"
|
||||||
|
[http.routers.test.tls]
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
store = ["default"]
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.consul]
|
[providers.consul]
|
||||||
|
|
|
@ -3,8 +3,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8080"
|
address = ":8080"
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8080"
|
address = ":8080"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
Rule = "Host(`test.local`)"
|
Rule = "Host(`test.local`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
middlewares = ["error"]
|
middlewares = ["error"]
|
||||||
|
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.error.errors]
|
[http.middlewares.error.errors]
|
||||||
status = ["500-502", "503-599"]
|
status = ["500-502", "503-599"]
|
||||||
service = "error"
|
service = "error"
|
||||||
query = "/50x.html"
|
query = "/50x.html"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:8989474"
|
url = "http://{{.Server1}}:8989474"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[services.error.loadbalancer]
|
[http.services.error.loadbalancer]
|
||||||
[[services.error.loadbalancer.servers]]
|
[[http.services.error.loadbalancer.servers]]
|
||||||
url = "http://{{.Server2}}:80"
|
url = "http://{{.Server2}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8080"
|
address = ":8080"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
Rule = "Host(`test.local`)"
|
Rule = "Host(`test.local`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
middlewares = ["error"]
|
middlewares = ["error"]
|
||||||
|
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.error.errors]
|
[http.middlewares.error.errors]
|
||||||
status = ["500-502", "503-599"]
|
status = ["500-502", "503-599"]
|
||||||
service = "error"
|
service = "error"
|
||||||
query = "/50x.html"
|
query = "/50x.html"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:80"
|
url = "http://{{.Server1}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[services.error.loadbalancer]
|
[http.services.error.loadbalancer]
|
||||||
[[services.error.loadbalancer.servers]]
|
[[http.services.error.loadbalancer.servers]]
|
||||||
url = "http://{{.Server2}}:80"
|
url = "http://{{.Server2}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.api]
|
[entrypoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entrypoints.web-secure.tls]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
[entryPoints]
|
[log]
|
||||||
[entryPoints.http]
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Path(`/test1`)"
|
rule = "Path(`/test1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.2:80"
|
url = "http://172.17.0.2:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router2]
|
[http.routers.router2]
|
||||||
rule = "Path(`/test2`)"
|
rule = "Path(`/test2`)"
|
||||||
service = "service2"
|
service = "service2"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service2.loadbalancer]
|
[http.services.service2.loadbalancer]
|
||||||
[[services.service2.loadbalancer.servers]]
|
[[http.services.service2.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.123:80"
|
url = "http://172.17.0.123:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[log]
|
[log]
|
||||||
|
@ -9,35 +9,35 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`test.localhost`)"
|
rule = "Host(`test.localhost`)"
|
||||||
service = "service2"
|
service = "service2"
|
||||||
|
|
||||||
[routers.router2]
|
[http.routers.router2]
|
||||||
rule = "Path(`/test`)"
|
rule = "Path(`/test`)"
|
||||||
middlewares = ["circuitbreaker"]
|
middlewares = ["circuitbreaker"]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.circuitbreaker.circuitbreaker]
|
[http.middlewares.circuitbreaker.circuitbreaker]
|
||||||
expression = "NetworkErrorRatio() > 0.5"
|
expression = "NetworkErrorRatio() > 0.5"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.2:80"
|
url = "http://172.17.0.2:80"
|
||||||
weight = 10
|
weight = 10
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.3:80"
|
url = "http://172.17.0.3:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[services.service2]
|
[http.services.service2]
|
||||||
[services.service2.loadbalancer]
|
[http.services.service2.loadbalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[[services.service2.loadbalancer.servers]]
|
[[http.services.service2.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.4:80"
|
url = "http://172.17.0.4:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[[services.service2.loadbalancer.servers]]
|
[[http.services.service2.loadbalancer.servers]]
|
||||||
url = "http://172.17.0.5:80"
|
url = "http://172.17.0.5:80"
|
||||||
weight = 2
|
weight = 2
|
||||||
|
|
|
@ -4,26 +4,27 @@ rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
[global]
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = """{{ .CertContent }}"""
|
|
||||||
keyFile = """{{ .KeyContent }}"""
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[tlsStores.default.DefaultCertificate]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -11,13 +10,13 @@ debug = true
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = """{{ .CertContent }}"""
|
|
||||||
keyFile = """{{ .KeyContent }}"""
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[tlsStores.default.DefaultCertificate]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
|
@ -5,28 +5,27 @@ insecureSkipVerify = true
|
||||||
[global]
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = """{{ .CertContent }}"""
|
|
||||||
keyFile = """{{ .KeyContent }}"""
|
|
||||||
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
|
[http.services]
|
||||||
[services]
|
[http.services.service1.loadbalancer]
|
||||||
[services.service1.loadbalancer]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
[[services.service1.loadbalancer.servers]]
|
|
||||||
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[tlsStores.default.DefaultCertificate]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
[serversTransport]
|
[serversTransport]
|
||||||
rootCAs = [ """{{ .CertContent }}""" ]
|
rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = """{{ .CertContent }}"""
|
|
||||||
keyFile = """{{ .KeyContent }}"""
|
|
||||||
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
middlewares = ["retryer"]
|
middlewares = ["retryer"]
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
[middlewares]
|
[http.middlewares]
|
||||||
[middlewares.retryer.retry]
|
[http.middlewares.retryer.retry]
|
||||||
Attempts = 2
|
Attempts = 2
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[services.service1.loadbalancer.responseForwarding]
|
[http.services.service1.loadbalancer.responseForwarding]
|
||||||
flushInterval="1ms"
|
flushInterval="1ms"
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[tlsStores.default.DefaultCertificate]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
|
@ -2,29 +2,27 @@
|
||||||
[serversTransport]
|
[serversTransport]
|
||||||
rootCAs = [ """{{ .CertContent }}""" ]
|
rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.DefaultCertificate]
|
|
||||||
certFile = """{{ .CertContent }}"""
|
|
||||||
keyFile = """{{ .KeyContent }}"""
|
|
||||||
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
rule = "Host(`127.0.0.1`)"
|
rule = "Host(`127.0.0.1`)"
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[services.service1.loadbalancer.responseForwarding]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
flushInterval="1ms"
|
|
||||||
[[services.service1.loadbalancer.servers]]
|
|
||||||
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[tlsStores.default.DefaultCertificate]
|
||||||
|
certFile = """{{ .CertContent }}"""
|
||||||
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http1]
|
[entrypoints.http1]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.http2]
|
[entrypoints.http2]
|
||||||
address = ":9000"
|
address = ":9000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -12,21 +12,21 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
Rule = "Host(`test.localhost`)"
|
Rule = "Host(`test.localhost`)"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[services.service1.loadbalancer.healthcheck]
|
[http.services.service1.loadbalancer.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
interval = "1s"
|
interval = "1s"
|
||||||
timeout = "0.9s"
|
timeout = "0.9s"
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:80"
|
url = "http://{{.Server1}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server2}}:80"
|
url = "http://{{.Server2}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http1]
|
[entrypoints.http1]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.http2]
|
[entrypoints.http2]
|
||||||
address = ":9000"
|
address = ":9000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -12,21 +12,21 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
Rule = "Host(`test.localhost`)"
|
Rule = "Host(`test.localhost`)"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
method = "wrr"
|
method = "wrr"
|
||||||
[services.service1.loadbalancer.healthcheck]
|
[http.services.service1.loadbalancer.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
interval = "1s"
|
interval = "1s"
|
||||||
timeout = "0.9s"
|
timeout = "0.9s"
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:80"
|
url = "http://{{.Server1}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server2}}:80"
|
url = "http://{{.Server2}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -10,19 +10,19 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
Rule = "Host(`test.localhost`)"
|
Rule = "Host(`test.localhost`)"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[services.service1.loadbalancer.healthcheck]
|
[http.services.service1.loadbalancer.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
port = 80
|
port = 80
|
||||||
interval = "1s"
|
interval = "1s"
|
||||||
timeout = "0.9s"
|
timeout = "0.9s"
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:81"
|
url = "http://{{.Server1}}:81"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.http]
|
[entrypoints.web]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -10,20 +10,20 @@ logLevel = "DEBUG"
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[http.routers]
|
||||||
[routers.router1]
|
[http.routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
Rule = "Host(`test.localhost`)"
|
Rule = "Host(`test.localhost`)"
|
||||||
|
|
||||||
[services]
|
[http.services]
|
||||||
[services.service1.loadbalancer]
|
[http.services.service1.loadbalancer]
|
||||||
[services.service1.loadbalancer.healthcheck]
|
[http.services.service1.loadbalancer.healthcheck]
|
||||||
path = "/health"
|
path = "/health"
|
||||||
interval = "1s"
|
interval = "1s"
|
||||||
timeout = "0.9s"
|
timeout = "0.9s"
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server1}}:80"
|
url = "http://{{.Server1}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[[services.service1.loadbalancer.servers]]
|
[[http.services.service1.loadbalancer.servers]]
|
||||||
url = "http://{{.Server2}}:80"
|
url = "http://{{.Server2}}:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
|
@ -1,50 +1,49 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.ClientCA]
|
|
||||||
files = ["fixtures/https/clientca/ca1.crt"]
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "service1"
|
Service = "service1"
|
||||||
Rule = "Host(`snitest.com`)"
|
Rule = "Host(`snitest.com`)"
|
||||||
[Routers.router2]
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
|
[http.routers.router2]
|
||||||
Service = "service2"
|
Service = "service2"
|
||||||
Rule = "Host(`snitest.org`)"
|
Rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router2.tls]
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.service1]
|
[http.services.service1]
|
||||||
[Services.service1.LoadBalancer]
|
[http.services.service1.LoadBalancer]
|
||||||
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
|
||||||
URL = "http://127.0.0.1:9010"
|
URL = "http://127.0.0.1:9010"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
[Services.service2]
|
|
||||||
[Services.service2.LoadBalancer]
|
|
||||||
|
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[http.services.service2]
|
||||||
|
[http.services.service2.LoadBalancer]
|
||||||
|
[[http.services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
[tlsOptions.default.ClientCA]
|
||||||
|
files = ["fixtures/https/clientca/ca1.crt"]
|
||||||
|
optional = true
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.ClientCA]
|
|
||||||
files = ["fixtures/https/clientca/ca1and2.crt"]
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "service1"
|
Service = "service1"
|
||||||
Rule = "Host(`snitest.com`)"
|
Rule = "Host(`snitest.com`)"
|
||||||
[Routers.router2]
|
[http.routers.router1.tls]
|
||||||
|
|
||||||
|
[http.routers.router2]
|
||||||
Service = "service2"
|
Service = "service2"
|
||||||
Rule = "Host(`snitest.org`)"
|
Rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router2.tls]
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.service1]
|
[http.services.service1]
|
||||||
[Services.service1.LoadBalancer]
|
[http.services.service1.LoadBalancer]
|
||||||
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
|
||||||
URL = "http://127.0.0.1:9010"
|
URL = "http://127.0.0.1:9010"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
[Services.service2]
|
|
||||||
[Services.service2.LoadBalancer]
|
|
||||||
|
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[http.services.service2]
|
||||||
|
[http.services.service2.LoadBalancer]
|
||||||
|
[[http.services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
[tlsOptions.default.ClientCA]
|
||||||
|
files = ["fixtures/https/clientca/ca1and2.crt"]
|
|
@ -2,49 +2,48 @@
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints]
|
||||||
[entryPoints.https]
|
[entrypoints.web-secure]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
|
||||||
[entryPoints.https.tls.ClientCA]
|
|
||||||
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
|
||||||
optional = false
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "service1"
|
Service = "service1"
|
||||||
Rule = "Host(`snitest.com`)"
|
Rule = "Host(`snitest.com`)"
|
||||||
[Routers.router2]
|
[http.routers.router1.tls]
|
||||||
|
[http.routers.router2]
|
||||||
Service = "service2"
|
Service = "service2"
|
||||||
Rule = "Host(`snitest.org`)"
|
Rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router2.tls]
|
||||||
|
|
||||||
[Services]
|
[http.services]
|
||||||
[Services.service1]
|
[http.services.service1]
|
||||||
[Services.service1.LoadBalancer]
|
[http.services.service1.LoadBalancer]
|
||||||
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
|
||||||
URL = "http://127.0.0.1:9010"
|
URL = "http://127.0.0.1:9010"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
[Services.service2]
|
|
||||||
[Services.service2.LoadBalancer]
|
|
||||||
|
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[http.services.service2]
|
||||||
|
[http.services.service2.LoadBalancer]
|
||||||
|
[[http.services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
[tlsOptions.default.ClientCA]
|
||||||
|
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
||||||
|
optional = false
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
[Routers]
|
[http.routers]
|
||||||
[Routers.router1]
|
[http.routers.router1]
|
||||||
Service = "service1"
|
service = "service1"
|
||||||
Rule = "Host(`snitest.com`)"
|
rule = "Host(`snitest.com`)"
|
||||||
[Routers.router2]
|
[http.routers.router1.tls]
|
||||||
Service = "service2"
|
|
||||||
Rule = "Host(`snitest.org`)"
|
|
||||||
|
|
||||||
[Services]
|
[http.routers.router2]
|
||||||
[Services.service1]
|
service = "service2"
|
||||||
[Services.service1.LoadBalancer]
|
rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router2.tls]
|
||||||
|
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
[http.services]
|
||||||
URL = "http://127.0.0.1:9010"
|
[http.services.service1]
|
||||||
Weight = 1
|
[http.services.service1.LoadBalancer]
|
||||||
[Services.service2]
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
[Services.service2.LoadBalancer]
|
url = "http://127.0.0.1:9010"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[http.services.service2]
|
||||||
URL = "http://127.0.0.1:9020"
|
[http.services.service2.LoadBalancer]
|
||||||
Weight = 1
|
[[http.services.service2.LoadBalancer.Servers]]
|
||||||
|
url = "http://127.0.0.1:9020"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
# bad certificates to validate the loop on the certificate appending
|
# bad certificates to validate the loop on the certificate appending
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
# bad content
|
# bad content
|
||||||
|
@ -36,7 +37,6 @@ w/X5M802XqzLjeec5zHoZDfknnAkgR9MsxZYmZPFaDyL6GOKUB8=
|
||||||
-----END RSA PRIVATE KEY-----"""
|
-----END RSA PRIVATE KEY-----"""
|
||||||
|
|
||||||
[[tls]]
|
[[tls]]
|
||||||
entryPoints = ["https"]
|
|
||||||
[tls.certificate]
|
[tls.certificate]
|
||||||
certFile = """-----BEGIN CERTIFICATE-----
|
certFile = """-----BEGIN CERTIFICATE-----
|
||||||
MIIC/zCCAeegAwIBAgIJALAYHG/vGqWEMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
|
MIIC/zCCAeegAwIBAgIJALAYHG/vGqWEMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
[log]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entrypoints]
|
||||||
|
[entrypoints.web-secure]
|
||||||
|
address = ":4443"
|
||||||
|
|
||||||
[entryPoints]
|
[entrypoints.https02]
|
||||||
[entryPoints.https]
|
address = ":8443"
|
||||||
address = ":4443"
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
[entryPoints.https02]
|
|
||||||
address = ":8443"
|
|
||||||
[entryPoints.https02.tls]
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
|
|