Traefik
Traefik is a reverse proxy/load balancer that is designed to handle dynamic configuration. It is designed to handle the complexities of routing traffic to multiple services and can be configured to automatically discover new services as they are added to the network.
Why use a reverse proxy?
- Automatic discovery of backends using container labels or service discovery mechanisms such as - Consul, etcd, and Kubernetes
- Built-in support for multiple load balancing algorithms, including round-robin, least connections, and IP hash
- Real-time monitoring and visualization of traffic using a web-based dashboard
- Support for HTTPS termination and automatic certificate generation using Let's Encrypt
- Ability to configure routing rules using a simple and flexible rule syntax
- Built-in support for circuit breaker and retries to improve service resilience
- Integration with Docker Swarm and Kubernetes for easy deployment and management in container orchestration environments.
Name | Desc |
---|---|
Dir | traefik |
Traefik Route | http://traefik.localhost |
Traefik Route | https://traefik.localhost |
Traefik Route | https://traefik.dev.localhost |
Normal Route | N/A |
Setup Traefik
Lets create a new folder for our services and create a docker-compose file for Traefik.
mkdir -p ~/local-cloud/traefik
Reference Proxy Network
Traefik will be our central point of entry for all services in our local cloud.
It will need to discover services on the proxy
network and be able to forward requests to them.
If the service you are trying to route to is not in the proxy
network,
Traefik will not be able to route to it and give a 404 response.
docker-compose.yml
networks:
proxy:
external: true
Traefik Service
Now lets add the docker container for Traefik to our docker-compose file.
networks:
proxy:
external: true
services:
traefik:
image: traefik:v3.0 #traefik:latest
container_name: traefik
hostname: traefik
restart: unless-stopped
environment:
- TZ=Etc/UTC
networks:
- proxy
ports:
- 80:80
- 443:443
- "6379:6379" # Optional TCP port
- "6380:6380" # Optional TCP port
volumes:
- "//var/run/docker.sock://var/run/docker.sock:ro"
Field | Desc | Reason |
---|---|---|
image | Traefik image to use | |
container_name | Name of the container | |
hostname | Hostname of the container | Allows containers to reference this by hostname instead of ip |
restart | Restart policy | restart unless stopped |
environment | Environment variables | add timezone var |
networks | Networks to attach to | Attach to proxy network for discovery |
ports | Ports to expose | expose 80 and 443, also optional tcp ports for dbs |
volumes | Volumes to mount | Mount docker socket or automatic service discovery |
//var/run/docker.sock://var/run/docker.sock:ro
- This volume is used to allow Traefik to communicate with the Docker daemon and discover new services as they are added with read only permissions on docker api.
Traefik Configuration
Now we need to make a traefik.yml file to configure Traefik to route traffic to our services. This will setup the Entrypoints and Metrics information for Traefik to use.
If otel collector isnt setup just ignore the settings for metrics right now. it will work later when you add the otel collector.
traefik.yml
api:
## Enable Dashboard
dashboard: true
insecure: true
debug: true
ping:
entryPoint: websecure
manualRouting: true
entryPoints:
## HTTP Entrypoint
web:
address: ":80"
forwardedHeaders:
insecure: true
http:
## Auto Redirect to HTTPS
redirections:
entryPoint:
to: websecure
scheme: https
## HTTPS Entrypoint
websecure:
address: ":443"
## TCP PORT
redis:
address: :6379
## TCP PORT
postgres:
address: :6380
serversTransport:
insecureSkipVerify: true
# rootCAs:
# - "/certs/ca.crt"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
## Must include traefik.enabled=true label
exposedByDefault: false
file:
filename: /config.yml
# redis:
# endpoints:
# - "redis:6379"
# rootKey: "traefik"
# username: "traefik"
log:
# filePath: /logs/traefik.log
format: json
noColor: true
level: DEBUG
maxSize: 1
maxBackups: 3
maxAge: 7
compress: true
## UnComment to Enable
# accessLog:
# filePath: "/logs/traefik_access.log"
# format: json
# bufferingSize: 100
# filters:
# statusCodes:
# - "400-404"
# - "500"
# retryAttempts: false
# minDuration: "150ms"
## UnComment to Enable
# metrics:
# otlp:
# explicitBoundaries:
# - 0.1
# - 0.3
# - 1.2
# - 5.0
# pushInterval: 10s
# http:
# endpoint: http://otelcol:4318/v1/metrics
# headers:
# foo: bar
# tls:
# ca: /certs/ca.crt
# insecureSkipVerify: true
# tracing:
# addInternals: true
# capturedRequestHeaders:
# - LOG_LEVEL
# otlp:
# http:
# endpoint: http://otelcol:4318/v1/traces
# headers:
# foo: bar
# tls:
# ca: /certs/ca.crt
# insecureSkipVerify: true
This will create 4 entrypoints
- web
- http port 80
- auto redirect to websecure
- websecure
- https port 443
- redis
- tcp port 6379
- postgres
- tcp port 6380
It will also setup the providers for Traefik to discover services using the docker socket
and a file configuration file that exists at /config.yml
in the container.
Traefik will look for a traefik.yml
in /traefik.yml and a config.yml
in /config.yml in the container.
Lets add those to our docker-compose file.
networks:
proxy:
external: true
services:
traefik:
image: traefik:v3.0 #traefik:latest
container_name: traefik
hostname: traefik
restart: unless-stopped
environment:
- TZ=Etc/UTC
networks:
- proxy
ports:
- 80:80
- 443:443
- "6379:6379" # TCP port
- "6380:6380" # TCP port
volumes:
- "//var/run/docker.sock://var/run/docker.sock:ro"
- "./traefik.yml:/traefik.yml"
- ./config.yml:/config.yml:ro
Traefik Configuration Static File
Now we need to create a config.yml
file that Traefik will use to discover services.
# tls:
# stores:
# default:
# defaultCertificate:
# certFile: /certs/localhost.pem
# keyFile: /certs/localhost-key.pem
# certificates:
# - certFile: /certs/localhost.pem
# keyFile: /certs/localhost-key.pem
http:
middlewares:
simpleRateLimit:
rateLimit:
average: 100 # maximum requests per second
period: 1 # 1s
burst: 200 # maximum number of requests in a small period of time
This is the place to add mTLS certs for traefik and a default cert if you have one.
Also creates a simple rate limit middleware that will limit requests to 100 per second with a burst of 200.
Traefik Labels
Now we can start our service but there is no way to access the dashboard. We need to add labels to our traefik service to allow access to the dashboard and ping service.
In our docker compose lets add these lables to the bottom of the traefik service.
services:
traefik:
image: traefik:v3.0 #traefik:latest
labels:
- "traefik.enable=true"
# Traefik Dashboard
- "traefik.http.routers.traefik_local.entrypoints=web,websecure"
- "traefik.http.routers.traefik_local.middlewares=simpleRateLimit@file"
- "traefik.http.routers.traefik_local.rule=( Host(`traefik.localhost`) || Host(`traefik.dev.localhost`) ) && ( PathPrefix(`/api`) || PathPrefix(`/dashboard`) )"
- "traefik.http.routers.traefik_local.tls=true"
- "traefik.http.routers.traefik_local.service=api@internal"
# Traefik Healthcheck
- "traefik.http.routers.traefik_ping.entrypoints=web,websecure"
- "traefik.http.routers.traefik_ping.rule=(Host(`traefik.localhost`) || Host(`traefik.dev.localhost`) ) && PathPrefix(`/ping`)"
- "traefik.http.routers.traefik_ping.tls=true"
- "traefik.http.routers.traefik_ping.service=ping@internal"
# Traefik API for internal containers
- "traefik.http.routers.traefiki.entrypoints=web,websecure"
- "traefik.http.routers.traefiki.rule=Host(`traefik`) && ( PathPrefix(`/api`) || PathPrefix(`/dashboard`) )"
- "traefik.http.routers.traefiki.tls=true"
- "traefik.http.routers.traefiki.service=api@internal"
# Traefik API Healthcheck for internal containers
- "traefik.http.routers.traefiki_ping.entrypoints=web,websecure"
- "traefik.http.routers.traefiki_ping.rule=Host(`traefik`) && PathPrefix(`/ping`)"
- "traefik.http.routers.traefiki_ping.tls=true"
- "traefik.http.routers.traefiki_ping.service=ping@internal"
# Traefik Redirect to HTTPS
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=websecure"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
This will allow access to the dashboard and ping service at traefik.localhost
and traefik.dev.localhost
respectively.
Internal Containers can also now access traefik using the traefik
hostname.
Start Traefik
Lets Start the container and see if it works.
docker compose up
You should now be able to access the traefik dashboard at http://traefik.localhost/dashboard/
and the ping service at http://traefik.localhost/ping/
Full Compose File
networks:
proxy:
external: true
services:
traefik:
image: traefik:v3.0 #traefik:latest
container_name: traefik
hostname: traefik
restart: unless-stopped
environment:
- TZ=Etc/UTC
networks:
- proxy
ports:
- 80:80
- 443:443
- "6379:6379" # TCP port
- "6380:6380" # TCP port
volumes:
- "//var/run/docker.sock://var/run/docker.sock:ro"
- "./certs/:/certs/"
- "./traefik.yml:/traefik.yml"
- ./config.yml:/config.yml:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik_local.entrypoints=web,websecure"
- "traefik.http.routers.traefik_local.middlewares=simpleRateLimit@file"
- "traefik.http.routers.traefik_local.rule=( Host(`traefik.localhost`) || Host(`traefik.dev.localhost`) ) && ( PathPrefix(`/api`) || PathPrefix(`/dashboard`) )"
- "traefik.http.routers.traefik_local.tls=true"
- "traefik.http.routers.traefik_local.service=api@internal"
- "traefik.http.routers.traefik_ping.entrypoints=web,websecure"
- "traefik.http.routers.traefik_ping.rule=(Host(`traefik.localhost`) || Host(`traefik.dev.localhost`) ) && PathPrefix(`/ping`)"
- "traefik.http.routers.traefik_ping.tls=true"
- "traefik.http.routers.traefik_ping.service=ping@internal"
- "traefik.http.routers.traefiki.entrypoints=web,websecure"
- "traefik.http.routers.traefiki.rule=Host(`traefik`) && ( PathPrefix(`/api`) || PathPrefix(`/dashboard`) )"
- "traefik.http.routers.traefiki.tls=true"
- "traefik.http.routers.traefiki.service=api@internal"
- "traefik.http.routers.traefiki_ping.entrypoints=web,websecure"
- "traefik.http.routers.traefiki_ping.rule=Host(`traefik`) && PathPrefix(`/ping`)"
- "traefik.http.routers.traefiki_ping.tls=true"
- "traefik.http.routers.traefiki_ping.service=ping@internal"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=websecure"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
Bonus Add Localhost Certs
To create certs check out this blog post