Routers

Connecting Requests to Services

routers

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 to update the request, or act before forwarding the request to the service.

Configuration Example

Requests /foo are Handled by service-foo — Using the File Provider

  1. [http.routers]
  2. [http.routers.my-router]
  3. rule = "Path(`/foo`)"
  4. service = "service-foo"
  1. http:
  2. routers:
  3. my-router:
  4. rule: "Path(`/foo`)"
  5. service: service-foo

With a middleware — using the File Provider

  1. [http.routers]
  2. [http.routers.my-router]
  3. rule = "Path(`/foo`)"
  4. # declared elsewhere
  5. middlewares = ["authentication"]
  6. service = "service-foo"
  1. http:
  2. routers:
  3. my-router:
  4. rule: "Path(`/foo`)"
  5. # declared elsewhere
  6. middlewares:
  7. - authentication
  8. service: service-foo

Forwarding all (non-tls) requests on port 3306 to a database service

  1. ## Static configuration ##
  2. [entryPoints]
  3. [entryPoints.web]
  4. address = ":80"
  5. [entryPoints.mysql-default]
  6. address = ":3306"
  7. ## Dynamic configuration ##
  8. [tcp]
  9. [tcp.routers]
  10. [tcp.routers.to-database]
  11. entryPoints = ["mysql-default"]
  12. # Catch every request (only available rule for non-tls routers. See below.)
  13. rule = "HostSNI(`*`)"
  14. service = "database"
  1. ## Static configuration ##
  2. entryPoints:
  3. web:
  4. address: ":80"
  5. mysql-default:
  6. address: ":3306"
  7. ## Dynamic configuration ##
  8. tcp:
  9. routers:
  10. to-database:
  11. entryPoints:
  12. - "mysql-default"
  13. # Catch every request (only available rule for non-tls routers. See below.)
  14. rule: "HostSNI(`*`)"
  15. service: database

Configuring HTTP Routers

EntryPoints

If not specified, HTTP routers will accept requests from all defined entry points.If you want to limit the router scope to a set of entry points, set the entryPoints option.Listens to Every EntryPoint

  1. ## Static configuration ##
  2. [entryPoints]
  3. [entryPoints.web]
  4. # ...
  5. [entryPoints.web-secure]
  6. # ...
  7. [entryPoints.other]
  8. # ...
  9. ## Dynamic configuration ##
  10. [http.routers]
  11. [http.routers.Router-1]
  12. # By default, routers listen to every entry points
  13. rule = "Host(`traefik.io`)"
  14. service = "service-1"
  1. ## Static configuration ##
  2. entryPoints:
  3. web:
  4. # ...
  5. web-secure:
  6. # ...
  7. other:
  8. # ...
  9. ## Dynamic configuration ##
  10. http:
  11. routers:
  12. Router-1:
  13. # By default, routers listen to every entry points
  14. rule: "Host(`traefik.io`)"
  15. service: "service-1"

Listens to Specific EntryPoints

  1. ## Static configuration ##
  2. [entryPoints]
  3. [entryPoints.web]
  4. # ...
  5. [entryPoints.web-secure]
  6. # ...
  7. [entryPoints.other]
  8. # ...
  9. ## Dynamic configuration ##
  10. [http.routers]
  11. [http.routers.Router-1]
  12. # won't listen to entry point web
  13. entryPoints = ["web-secure", "other"]
  14. rule = "Host(`traefik.io`)"
  15. service = "service-1"
  1. ## Static configuration ##
  2. entryPoints:
  3. web:
  4. # ...
  5. web-secure:
  6. # ...
  7. other:
  8. # ...
  9. ## Dynamic configuration ##
  10. http:
  11. routers:
  12. Router-1:
  13. # won't listen to entry point web
  14. entryPoints:
  15. - "web-secure"
  16. - "other"
  17. rule: "Host(`traefik.io`)"
  18. service: "service-1"

Rule

Rules are a set of matchers that determine if a particular request matches specific criteria.If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service.Host is traefik.io

  1. rule = "Host(`traefik.io`)"

Host is traefik.io OR Host is containo.us AND path is /traefik

  1. rule = "Host(`traefik.io`) || (Host(`containo.us`) && Path(`/traefik`))"

The table below lists all the available matchers:

RuleDescription
Headers(key, value)Check if there is a key keydefined in the headers, with the value value
HeadersRegexp(key, regexp)Check if there is a key keydefined 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(GET, …)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.

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 may be used (example: /posts/{id:[0-9]+}).

Combining Matchers Using Operators and Parenthesis

You can combine multiple matchers using the AND (&&) and OR (||) operators. You can also use parenthesis.

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.

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 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 per router.Services are the target for the router.

HTTP Only

HTTP routers can only target HTTP services (not TCP services).

TLS

General

When a TLS section is specified, it instructs 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).Configuring the router to accept HTTPS requests only

  1. [http.routers]
  2. [http.routers.Router-1]
  3. rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
  4. service = "service-id"
  5. # will terminate the TLS request
  6. [http.routers.Router-1.tls]
  1. http:
  2. routers:
  3. Router-1:
  4. rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
  5. service: service-id
  6. # will terminate the TLS request
  7. tls: {}

HTTPS & ACME

In the current version, with ACME enabled, automatic certificate generation will apply to every router declaring a TLS section.

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.HTTP & HTTPS routes

  1. [http.routers]
  2. [http.routers.my-https-router]
  3. rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
  4. service = "service-id"
  5. # will terminate the TLS request
  6. [http.routers.my-https-router.tls]
  7. [http.routers.my-http-router]
  8. rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
  9. service = "service-id"
  1. http:
  2. routers:
  3. my-https-router:
  4. rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
  5. service: service-id
  6. # will terminate the TLS request
  7. tls: {}
  8. my-http-router:
  9. rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
  10. service: service-id

options

The options field enables fine-grained control of the TLS parameters.It refers to a TLS Options and will be applied only if a Host rule is defined.

Server Name Association

Even though one might get the impression that a TLS options reference is mapped to a router, or a router rule, one should realize that it is actually mapped only to the host name found in the Host part of the rule. Of course, there could also be several Host parts in a rule, in which case the TLS options reference would be mapped to as many host names.

Another thing to keep in mind is: the TLS option is picked from the mapping mentioned above and based on the server name provided during the TLS handshake, and it all happens before routing actually occurs.

Configuring the TLS options

  1. [http.routers]
  2. [http.routers.Router-1]
  3. rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
  4. service = "service-id"
  5. # will terminate the TLS request
  6. [http.routers.Router-1.tls]
  7. options = "foo"
  8. [tls.options]
  9. [tls.options.foo]
  10. minVersion = "VersionTLS12"
  11. cipherSuites = [
  12. "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
  13. "TLS_RSA_WITH_AES_256_GCM_SHA384"
  14. ]
  1. http:
  2. routers:
  3. Router-1:
  4. rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
  5. service: service-id
  6. # will terminate the TLS request
  7. tls:
  8. options: foo
  9. tls:
  10. options:
  11. foo:
  12. minVersion: VersionTLS12
  13. cipherSuites:
  14. - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  15. - TLS_RSA_WITH_AES_256_GCM_SHA384

Conflicting TLS Options

Since a TLS options reference is mapped to a host name, if a configuration introduces a situation where the same host name (from a Host rule) gets matched with two TLS options references, a conflict occurs, such as in the example below:

  1. [http.routers]
  2. [http.routers.routerfoo]
  3. rule = "Host(`snitest.com`) && Path(`/foo`)"
  4. [http.routers.routerfoo.tls]
  5. options = "foo"
  6. [http.routers]
  7. [http.routers.routerbar]
  8. rule = "Host(`snitest.com`) && Path(`/bar`)"
  9. [http.routers.routerbar.tls]
  10. options = "bar"
  1. http:
  2. routers:
  3. routerfoo:
  4. rule: "Host(`snitest.com`) && Path(`/foo`)"
  5. tls:
  6. options: foo
  7. routerbar:
  8. rule: "Host(`snitest.com`) && Path(`/bar`)"
  9. tls:
  10. options: bar

If that happens, both mappings are discarded, and the host name (snitest.com in this case) for these routers gets associated with the default TLS options instead.

certResolver

If certResolver is defined, Traefik will try to generate certificates based on routers Host & HostSNI rules.

  1. [http.routers]
  2. [http.routers.routerfoo]
  3. rule = "Host(`snitest.com`) && Path(`/foo`)"
  4. [http.routers.routerfoo.tls]
  5. certResolver = "foo"
  1. http:
  2. routers:
  3. routerfoo:
  4. rule: "Host(`snitest.com`) && Path(`/foo`)"
  5. tls:
  6. certResolver: foo

Multiple Hosts in a Rule

The rule Host(test1.traefik.io,test2.traefik.io) will request a certificate with the main domain test1.traefik.io and SAN test2.traefik.io.

domains

You can set SANs (alternative domains) for each main domain.Every domain must have A/AAAA records pointing to Traefik.Each domain & SAN will lead to a certificate request.

  1. [http.routers]
  2. [http.routers.routerbar]
  3. rule = "Host(`snitest.com`) && Path(`/bar`)"
  4. [http.routers.routerbar.tls]
  5. certResolver = "bar"
  6. [[http.routers.routerbar.tls.domains]]
  7. main = "snitest.com"
  8. sans = "*.snitest.com"
  1. http:
  2. routers:
  3. routerbar:
  4. rule: "Host(`snitest.com`) && Path(`/bar`)"
  5. tls:
  6. certResolver: "bar"
  7. domains:
  8. - main: "snitest.com"
  9. sans: "*.snitest.com"

ACME v2 supports wildcard certificates.As described in Let's Encrypt's post wildcard certificates can only be generated through a DNS-01 challenge.

Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 DNS-01 challenges are executed.In this case the generated DNS TXT record for both domains is the same.Even though this behavior is DNS RFC compliant,it can lead to problems as all DNS providers keep DNS records cached for a given time (TTL) and this TTL can be greater than the challenge timeout making the DNS-01 challenge fail.

The Traefik ACME client library LEGO supports some but not all DNS providers to work around this issue.The Supported provider table indicates if they allow generating certificates for a wildcard domain and its root domain.

Note

Wildcard certificates can only be verified through a DNS-01 challenge.

Double Wildcard Certificates

It is not possible to request a double wildcard certificate for a domain (for example ..local.com).

Configuring TCP Routers

General

If both HTTP routers and TCP routers listen to the same entry points, 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 entry points.If you want to limit the router scope to a set of entry points, set the entry points option.Listens to Every Entry Point

  1. ## Static configuration ##
  2. [entryPoints]
  3. [entryPoints.web]
  4. # ...
  5. [entryPoints.web-secure]
  6. # ...
  7. [entryPoints.other]
  8. # ...
  9. ## Dynamic configuration ##
  10. [tcp.routers]
  11. [tcp.routers.Router-1]
  12. # By default, routers listen to every entrypoints
  13. rule = "HostSNI(`traefik.io`)"
  14. service = "service-1"
  15. # will route TLS requests (and ignore non tls requests)
  16. [tcp.routers.Router-1.tls]
  1. ## Static configuration ##
  2. entryPoints:
  3. web:
  4. # ...
  5. web-secure:
  6. # ...
  7. other:
  8. # ...
  9. ## Dynamic configuration ##
  10. tcp:
  11. routers:
  12. Router-1:
  13. # By default, routers listen to every entrypoints
  14. rule: "HostSNI(`traefik.io`)"
  15. service: "service-1"
  16. # will route TLS requests (and ignore non tls requests)
  17. tls: {}

Listens to Specific Entry Points

  1. ## Static configuration ##
  2. [entryPoints]
  3. [entryPoints.web]
  4. # ...
  5. [entryPoints.web-secure]
  6. # ...
  7. [entryPoints.other]
  8. # ...
  9. ## Dynamic configuration ##
  10. [tcp.routers]
  11. [tcp.routers.Router-1]
  12. # won't listen to entry point web
  13. entryPoints = ["web-secure", "other"]
  14. rule = "HostSNI(`traefik.io`)"
  15. service = "service-1"
  16. # will route TLS requests (and ignore non tls requests)
  17. [tcp.routers.Router-1.tls]
  1. ## Static configuration ##
  2. entryPoints:
  3. web:
  4. # ...
  5. web-secure:
  6. # ...
  7. other:
  8. # ...
  9. ## Dynamic configuration ##
  10. tcp:
  11. routers:
  12. Router-1:
  13. # won't listen to entry point web
  14. entryPoints:
  15. - "web-secure"
  16. - "other"
  17. rule: "HostSNI(`traefik.io`)"
  18. service: "service-1"
  19. # will route TLS requests (and ignore non tls requests)
  20. tls: {}

Rule

RuleDescription
HostSNI(domain-1, …)Check if the Server Name Indication corresponds to the given domains.

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 per TCP router.Services are the target for the router.

TCP Only

TCP routers can only target TCP services (not HTTP services).

TLS

General

When a TLS section is specified, it instructs 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 Traefik can be configured in order to let the requests pass through (keeping the data encrypted), and be forwarded to the service "as is".Configuring TLS Termination

  1. [tcp.routers]
  2. [tcp.routers.Router-1]
  3. rule = "HostSNI(`foo-domain`)"
  4. service = "service-id"
  5. # will terminate the TLS request by default
  6. [tcp.routers.Router-1.tls]
  1. tcp:
  2. routers:
  3. Router-1:
  4. rule: "HostSNI(`foo-domain`)"
  5. service: service-id
  6. # will terminate the TLS request by default
  7. tls: {}

Configuring passthrough

  1. [tcp.routers]
  2. [tcp.routers.Router-1]
  3. rule = "HostSNI(`foo-domain`)"
  4. service = "service-id"
  5. [tcp.routers.Router-1.tls]
  6. passthrough = true
  1. tcp:
  2. routers:
  3. Router-1:
  4. rule: "HostSNI(`foo-domain`)"
  5. service: service-id
  6. tls:
  7. passthrough: true

TLS & ACME

In the current version, with ACME enabled, automatic certificate generation will apply to every router declaring a TLS section.

options

The options field enables fine-grained control of the TLS parameters.It refers to a TLS Options and will be applied only if a HostSNI rule is defined.Configuring the tls options

  1. [tcp.routers]
  2. [tcp.routers.Router-1]
  3. rule = "HostSNI(`foo-domain`)"
  4. service = "service-id"
  5. # will terminate the TLS request
  6. [tcp.routers.Router-1.tls]
  7. options = "foo"
  8. [tls.options]
  9. [tls.options.foo]
  10. minVersion = "VersionTLS12"
  11. cipherSuites = [
  12. "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
  13. "TLS_RSA_WITH_AES_256_GCM_SHA384"
  14. ]
  1. tcp:
  2. routers:
  3. Router-1:
  4. rule: "HostSNI(`foo-domain`)"
  5. service: service-id
  6. # will terminate the TLS request
  7. tls:
  8. options: foo
  9. tls:
  10. options:
  11. foo:
  12. minVersion: VersionTLS12
  13. cipherSuites:
  14. - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
  15. - "TLS_RSA_WITH_AES_256_GCM_SHA384"

certResolver

See certResolver for HTTP router for more information.

  1. [tcp.routers]
  2. [tcp.routers.routerfoo]
  3. rule = "HostSNI(`snitest.com`)"
  4. [tcp.routers.routerfoo.tls]
  5. certResolver = "foo"
  1. tcp:
  2. routers:
  3. routerfoo:
  4. rule: "HostSNI(`snitest.com`)"
  5. tls:
  6. certResolver: foo

domains

See domains for HTTP router for more information.

  1. [tcp.routers]
  2. [tcp.routers.routerbar]
  3. rule = "HostSNI(`snitest.com`)"
  4. [tcp.routers.routerbar.tls]
  5. certResolver = "bar"
  6. [[tcp.routers.routerbar.tls.domains]]
  7. main = "snitest.com"
  8. sans = "*.snitest.com"
  1. tcp:
  2. routers:
  3. routerbar:
  4. rule: "HostSNI(`snitest.com`)"
  5. tls:
  6. certResolver: "bar"
  7. domains:
  8. - main: "snitest.com"
  9. sans: "*.snitest.com"