Skip to main content

Traefik

src

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.
NameDesc
Dirtraefik
Traefik Routehttp://traefik.localhost
Traefik Routehttps://traefik.localhost
Traefik Routehttps://traefik.dev.localhost
Normal RouteN/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"

FieldDescReason
imageTraefik image to use
container_nameName of the container
hostnameHostname of the containerAllows containers to reference this by hostname instead of ip
restartRestart policyrestart unless stopped
environmentEnvironment variablesadd timezone var
networksNetworks to attach toAttach to proxy network for discovery
portsPorts to exposeexpose 80 and 443, also optional tcp ports for dbs
volumesVolumes to mountMount 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/

src

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

Youtube Video