traefik
14 min read
Traefik is an open-source Edge Router (Reverse Proxy) that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.
Traefik is based on the concept of EntryPoints, Routers, Middlewares and Services.
• EntryPoints: EntryPoints are the network entry points into Traefik. They define the port which will receive the packets, and whether to listen for TCP or UDP.
• Routers: A router is in charge of connecting incoming requests to the services that can handle them.
• Middlewares: Attached to the routers, middlewares can modify the requests or responses before they are sent to your service
• Services: Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
Docker Compose
yaml
version: "3"
services:
traefik:
image: traefik:v2.10.4
ports:
- 80:80
- 443:443
- 28080:8080
volumes:
- ./conf:/etc/traefik
- ./logs:/var/log/traefik/
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
Configuration
Configuration is done via the file traefik.yaml.
Entrypoints
You need to define some entrypoints which accept incoming traffik.
yaml
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
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. Routers can handle HTTP, TCP and UDP traffik.
Example:
yaml
http:
routers:
my-router:
rule: "Path(`/foo`)"
service: service-foo
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.
Listen only to specific entrypoints:
yaml
http:
routers:
Router-1:
# won't listen to entry point web
entryPoints:
- "websecure"
- "other"
rule: "Host(`example.com`)"
service: "service-1"
Rules
Rules are a set of matchers configured with values, 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.
yaml
http:
routers:
Router:
rule: "Host(`example.com`)"
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(`example.com`, ...) | Check if the request domain (host header value) targets one of the given domains. |
| HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...) | Match the request domain |
| Method(`GET`, ...) | Check if the request method is one of the given methods (GET, POST, PUT, DELETE, PATCH, HEAD) |
| Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...) | Match exact request path |
PathPrefix(/products/, /articles/{cat:[a-z]+}/{id:[0-9]+}) | Match request prefix path |
| Query(`foo=bar`, `bar=baz`) | Match Query String parameters. It accepts a sequence of key=value pairs. |
| ClientIP(`10.0.0.0/16`, `::1`) | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. |
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.
yaml
http:
routers:
my-router:
rule: "Path(`/foo`)"
middlewares:
- authentication
service: service-foo
Service
Each request must eventually be handled by a service, which is why each router definition should include a service target, which is basically where the request will be passed along to.
In general, a service assigned to a router should have been defined, but there are exceptions for label-based providers.
TLS
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).
yaml
http:
routers:
Router-1:
rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
service: service-id
# will terminate the TLS request
tls: {}
• certResolver If certResolver is defined, Traefik will try to generate certificates based on routers Host & HostSNI rules.
yaml
http:
routers:
routerfoo:
rule: "Host(`snitest.com`) && Path(`/foo`)"
tls:
certResolver: foo
• 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.
yaml
http:
routers:
routerbar:
rule: "Host(`snitest.com`) && Path(`/bar`)"
tls:
certResolver: "bar"
domains:
- main: "snitest.com"
sans:
- "*.snitest.com"
Services
The Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.
Example:
yaml
http:
services:
my-service:
loadBalancer:
servers:
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
- url: "http://<private-ip-server-2>:<private-port-server-2>/"
tcp:
services:
my-service:
loadBalancer:
servers:
- address: "<private-ip-server-1>:<private-port-server-1>"
- address: "<private-ip-server-2>:<private-port-server-2>"
Load Balancing
Traefik can load balance across multiple servers with the loadBalancer.servers list.
yaml
http:
services:
my-service:
loadBalancer:
servers:
- url: "http://server1:8080"
- url: "http://server2:8080
Servers Transport
serversTransport allows to reference a ServersTransport configuration for the communication between Traefik and your servers.
yaml
http:
services:
Service01:
loadBalancer:
serversTransport: mytransport
Define a serverTransport configuration:
yaml
http:
serversTransports:
mytransport:
You can define root CAs used for verifying SSL between traefik and your servers:
yaml
http:
serversTransports:
mytransport:
rootCAs:
- foo.crt
- bar.crt
Or skip SSL verification:
yaml
http:
serversTransports:
mytransport:
insecureSkipVerify: true
TLS
Traefik supports HTTPS & TLS, which concerns roughly two parts of the configuration: routers, and the TLS connection (and its underlying certificates).
Traefik requires you to define "Certificate Resolvers" in the static configuration, which are responsible for retrieving certificates from an ACME server.
On Kubernetes, certificate resolvers are usually replaced by cert-manager, which issues certificates into TLS Secrets that Traefik then simply consumes.
yaml
certificatesResolvers:
myresolver:
# Enable ACME (Let's Encrypt): automatic SSL.
acme:
email: "test@example.com"
# File or key used for certificates storage.
storage: "acme.json"
# The certificates' duration in hours.
# It defaults to 2160 (90 days) to follow Let's Encrypt certificates' duration.
#
# Optional
# Default: 2160
#
certificatesDuration: 2160
# Use a TLS-ALPN-01 ACME challenge.
#
# Optional (but recommended)
#
tlsChallenge:
# Use a HTTP-01 ACME challenge.
#
# Optional
#
httpChallenge:
# EntryPoint to use for the HTTP-01 challenges.
#
# Required
#
entryPoint: web
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
# Note: mandatory for wildcard certificate generation.
#
# Optional
#
dnsChallenge:
# DNS provider used.
#
# Required
#
provider: digitalocean
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
# Useful if internal networks block external DNS queries.
#
# Optional
# Default: 0
#
delayBeforeCheck: 0
# Use following DNS servers to resolve the FQDN authority.
#
# Optional
# Default: empty
#
resolvers
- "1.1.1.1:53"
- "8.8.8.8:53"
Middlewares
Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your service (or before the answer from the services are sent to the clients).
yaml
http:
routers:
router1:
service: myService
middlewares:
- "foo-add-prefix"
rule: "Host(`example.com`)"
middlewares:
foo-add-prefix:
addPrefix:
prefix: "/foo"
services:
service1:
loadBalancer:
servers:
- url: "http://127.0.0.1:80"
HTTP Middlewares
Add Prefix
The AddPrefix middleware updates the path of a request before forwarding it. So http://domain/path would be http://domain/prefix/path if used.
yaml
http:
middlewares:
add-foo:
addPrefix:
prefix: "/prefix"
BasicAuth
The BasicAuth middleware grants access to services to authorized users only.
• users The users option is an array of authorized users. Each user must be declared using the name:hashed-password format.
yaml
http:
middlewares:
test-auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
• usersFile The usersFile option is the path to an external file that contains the authorized users for the middleware.
yaml
http:
middlewares:
test-auth:
basicAuth:
usersFile: "/path/to/my/usersfile"
• headerField You can define a header field to store the authenticated user using the headerFieldoption.
yaml
http:
middlewares:
my-auth:
basicAuth:
# ...
headerField: "X-WebAuth-User"
• removeHeader Set the removeHeader option to true to remove the authorization header before forwarding the request to your service. (Default value is false.)
Compress
Compress Responses before Sending them to the Client. The Compress middleware uses gzip compression.
• excludedContentTypes specifies a list of content types to compare the Content-Type header of the incoming requests and responses before compressing. The responses with content types defined in excludedContentTypes are not compressed.
• minResponseBodyBytes specifies the minimum amount of bytes a response body must have to be compressed. The default value is 1024, which should be a reasonable value for most cases.
yaml
http:
middlewares:
test-compress:
compress:
excludedContentTypes:
- text/event-stream
minResponseBodyBytes: 1200
ContentType
The Content-Type middleware - or rather its autoDetect option - specifies whether to let the Content-Type header, if it has not been defined by the backend, be automatically set to a value derived from the contents of the response.
yaml
http:
middlewares:
autodetect:
contentType:
autoDetect: true
DigestAuth
Adding Digest Authentication. The configuration options are the same as BasicAuth middleware.
yaml
http:
middlewares:
test-auth:
digestAuth:
users:
- "test:traefik:a2688e031edb4be6a3797f3882655c05"
- "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
Errors
The Errors middleware returns a custom page in lieu of the default, according to configured ranges of HTTP Status codes.
yaml
http:
middlewares:
test-errors:
errors:
status:
- "500"
- "501"
- "503"
- "505-599"
service: serviceError
query: "/{status}.html"
• status The status option defines which status or range of statuses should result in an error page. The status code ranges are inclusive (505-599 will trigger with every code between 505 and 599, 505 and 599 included).
• service The service that will serve the new requested error page.
• query The URL for the error page (hosted by service). There are multiple variables that can be placed in the query option to insert values in the URL. The table below lists all the available variables and their associated values.
| Variable | Value |
|---|---|
{status} | The response status code. |
{url} | The escaped request URL. |
ForwardAuth
The ForwardAuth middleware delegates authentication to an external service. If the service answers with a 2XX code, access is granted, and the original request is performed. Otherwise, the response from the authentication server is returned.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
Forward-Request Headers
The following request properties are provided to the forward-auth target endpoint as X-Forwarded- headers:
| Property | Forward-Request Header |
|---|---|
| HTTP Method | X-Forwarded-Method |
| Protocol | X-Forwarded-Proto |
| Host | X-Forwarded-Host |
| Request URI | X-Forwarded-Uri |
| Source IP-Address | X-Forwarded-For |
• address: The address option defines the authentication server address.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
• trustForwardHeader Set the trustForwardHeader option to true to trust all X-Forwarded-* headers.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
trustForwardHeader: true
• authResponseHeaders The authResponseHeaders option is the list of headers to copy from the authentication server response and set on forwarded request, replacing any existing conflicting headers.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
authResponseHeaders:
- "X-Auth-User"
- "X-Secret"
• authResponseHeadersRegex The authResponseHeadersRegex option is the regex to match headers to copy from the authentication server response and set on forwarded request, after stripping all headers that match the regex.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
authResponseHeadersRegex: "^X-"
• authRequestHeaders The authRequestHeaders option is the list of the headers to copy from the request to the authentication server. It allows filtering headers that should not be passed to the authentication server. If not set or empty then all request headers are passed.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
authRequestHeaders:
- "Accept"
- "X-CustomHeader"
• tls Defines the TLS configuration used for the secure connection to the authentication server.
yaml
http:
middlewares:
test-auth:
forwardAuth:
address: "https://example.com/auth"
tls:
# CA used for SSL
ca: "path/to/local.crt"
# Skip SSL
insecureSkipVerify: true
Headers
Managing Request/Response headers
yaml
http:
middlewares:
testHeader:
headers:
customRequestHeaders:
X-Script-Name: "test"
customResponseHeaders:
X-Custom-Response-Header: "value"
• Add/Remove Headers
yaml
http:
middlewares:
testHeader:
headers:
customRequestHeaders:
X-Script-Name: "test" # Adds
X-Custom-Request-Header: "" # Removes
customResponseHeaders:
X-Custom-Response-Header: "" # Removes
• CORS Headers
yaml
http:
middlewares:
testHeader:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlAllowHeaders: "*"
accessControlAllowOriginList:
- https://foo.bar.org
- https://example.org
accessControlMaxAge: 100
addVaryHeader: true
IPWhiteList
Limiting Clients to Specific IPs IPWhitelist accepts / refuses requests based on the client IP.
yaml
http:
middlewares:
test-ipwhitelist:
ipWhiteList:
sourceRange:
- "127.0.0.1/32"
- "192.168.1.7"
Ratelimit
The RateLimit middleware ensures that services will receive a fair amount of requests, and allows one to define what fair is.
It is based on a token bucket implementation. In this analogy, the average parameter (defined below) is the rate at which the bucket refills, and the burst is the size (volume) of the bucket.
yaml
http:
middlewares:
test-ratelimit:
rateLimit:
average: 100
burst: 50
• average average is the maximum rate, by default in requests per second, allowed from a given source. It defaults to 0, which means no rate limiting. The rate is actually defined by dividing average by period.
• period period, in combination with average, defines the actual maximum rate. It defaults to 1 second.
• burst burst is the maximum number of requests allowed to go through in the same arbitrarily small period of time. It defaults to 1.
You can exclude IPs from rate limiting:
yaml
http:
middlewares:
test-ratelimit:
rateLimit:
sourceCriterion:
ipStrategy:
excludedIPs:
- "127.0.0.1/32"
- "192.168.1.7"
RedirectScheme
The RedirectScheme middleware redirects the request if the request scheme is different from the configured scheme.
yaml
http:
middlewares:
test-redirectscheme:
redirectScheme:
scheme: https
permanent: true
RedirectRegex
The RedirectRegex redirects a request using regex matching and replacement.
yaml
http:
middlewares:
test-redirectregex:
redirectRegex:
regex: "^http://localhost/(.*)"
replacement: "http://mydomain/${1}"
ReplacePath
The ReplacePath middleware will:
• replace the actual path with the specified one.
• store the original path in a X-Replaced-Path header.
yaml
http:
middlewares:
test-replacepath:
replacePath:
path: "/foo"
ReplacePathRegex
The ReplacePathRegex middleware will:
• replace the matching path with the specified one.
• store the original path in a X-Replaced-Path header.
yaml
http:
middlewares:
test-replacepathregex:
replacePathRegex:
regex: "^/foo/(.*)"
replacement: "/bar/$1"
Retry
The Retry middleware reissues requests a given number of times to a backend server if that server does not reply. As soon as the server answers, the middleware stops retrying, regardless of the response status. The Retry middleware has an optional configuration to enable an exponential backoff.
yaml
http:
middlewares:
test-retry:
retry:
attempts: 4
initialInterval: 100ms
StripPrefix
Remove the specified prefixes from the URL path.
yaml
http:
middlewares:
test-stripprefix:
stripPrefix:
prefixes:
- "/foobar"
- "/fiibar"
StripPrefixRegex
Remove the matching prefixes from the URL path.
yaml
http:
middlewares:
test-stripprefixregex:
stripPrefixRegex:
regex:
- "/foo/[a-z0-9]+/[0-9]+/"
Access log
Access logs allow you to keep track of what request are made to your server.
To enable the access logs:
yaml
accessLog: {}
• filePath: By default access logs are written to the standard output. To write the logs into a log file, use the filePath option.
yaml
accessLog:
filePath: "/path/to/access.log"
• format: By default, logs are written using the Common Log Format (CLF). To write logs in JSON, use json in the format option. If the given format is unsupported, the default (CLF) is used instead.
Common Log Format
<remote_IP_address> - <client_user_name_if_available> <timestamp> "<request_method> <request_path> <request_protocol>" <HTTP_status> <content-length> "<request_referrer>" "<request_user_agent>" <number_of_requests_received_since_Traefik_started> "<Traefik_router_name>" "<Traefik_server_URL>" <request_duration_in_ms>m
• bufferingSize To write the logs in an asynchronous fashion, specify a bufferingSize option. This option represents the number of log lines Traefik will keep in memory before writing them to the selected output. In some cases, this option can greatly help performances.
yaml
# Configuring a buffer of 100 lines
accessLog:
filePath: "/path/to/access.log"
bufferingSize: 100
Filtering
To filter logs, you can specify a set of filters which are logically "OR-connected". Thus, specifying multiple filters will keep more access logs than specifying only one. The available filters are:
• statusCodes, to limit the access logs to requests with a status codes in the specified range
• retryAttempts, to keep the access logs when at least one retry has happened
• minDuration, to keep access logs when requests take longer than the specified duration (provided in seconds or as a valid duration format)
yaml
# Configuring Multiple Filters
accessLog:
filePath: "/path/to/access.log"
format: json
filters:
statusCodes:
- "200"
- "300-302"
retryAttempts: true
minDuration: "10ms"
Limiting the Fields/Including Headers
You can decide to limit the logged fields/headers to a given list with the fields.names and fields.headers options.
Each field can be set to:
• keep to keep the value
• drop to drop the value
• redact to replace the value with "redacted"
The defaultMode for fields.names is keep.
The defaultMode for fields.headers is drop.
yaml
# Limiting the Logs to Specific Fields
accessLog:
filePath: "/path/to/access.log"
format: json
fields:
defaultMode: keep
names:
ClientUsername: drop
headers:
defaultMode: keep
names:
User-Agent: redact
Authorization: drop
Content-Type: keep