February 9, 2023
This quick post will only focus on setting up Traefik as a routing solution for your web services on a single Docker hosts. Will also help you generate your LetsEncrypt powered certificates.
What i expose here is not a solution for big projects by any means, it will help you understand what Traefik does best and (like in my case) help me deploy those 'toy-like' projects, maybe some demos for your clients without having to setup a massive architecture with K8 or similar.
TLDR: Demo project here: Github @ danielm/traefik-reverse-proxy
Its a reverse proxy, an edge router and load balancer designed to simplify the deployment of microservices and containers. It automatically detects and configures itself based on the services running on your infrastructure.
It supports many backends like (in this example) docker as a single host running locally, but also Kubernetes, Mesos and others...
Some cool features:
First let's create a network for our services:
$ docker network create traefik-proxy
And also a volume to keep the LetsEncrypt data
$ docker volume create letsencrypt-data
We will use docker compose to keep things clean, let's have a look:
services:
traefik:
image: traefik:2.9
restart: unless-stopped
container_name: traefik-proxy
ports:
- 80:80
- 443:443
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik.yml:/traefik.yml:ro"
- "./traefik_dyn.yml:/traefik_dyn.yml:ro"
- "./.htpasswd:/.htpasswd:ro"
- "letsencrypt:/letsencrypt"
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`traefik.localhost`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth@file"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsEncryptResolver"
networks:
default:
name: traefik-proxy
external: true
volumes:
letsencrypt:
name: letsencrypt-data
external: true
Now let's review each important concept and the rest of the config. Imagine we want to build something like this:
Looking at the config we see that Traefik will handle all incoming HTTP and HTTPS connections, and redirect based on the rules to each configured service.
Important: Traefik is smart enough to detect what PORTS each of your services (containers) EXPOSE and assign these incoming requests to the right service.
These are basically the config files we use
Elements in the static configuration set up connections to providers and define the entrypoints Traefik will listen to (these elements don't change often).
The dynamic configuration contains everything that defines how the requests are handled by your system. This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.
Mostly is self explanatory but the key concepts to understand are are:
## Static Configuration
##
## file: traefik.yml
log:
level: INFO
api:
#insecure: true
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
forwardedHeaders:
insecure: true
http:
tls:
certResolver: letsEncryptResolver
certificatesResolvers:
letsEncryptResolver:
acme:
## TODO: Set your e-mail here
email: "username@emailserver.com"
storage: "/letsencrypt/acme.json"
tlschallenge: true
# Uncomment when testing
#caServer: https://acme-staging-v02.api.letsencrypt.org/directory
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
watch: true
network: traefik-proxy
file:
filename: /traefik_dyn.yml
watch: true
Once we are done and have our traefik proxy container up and runing, we can start using it to access the rest of our services in our host.
In the docker-compose file on each of our project we need to add a few labels and restart our containers.
Key points here:
# example of our
# docker-compose of our projects
##
services:
mynodeapp:
image: node:19
# .... rest of whatever our project does
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-app.entrypoints=websecure"
- "traefik.http.routers.my-app.rule=Host(`mystartup.com`)"
I'm a 32-years old programmer and web developer currently living in Montevideo, Uruguay. I been programming since I was about 15 y.o, and for the past 12 actively working in the area.