Traefik: Docker routing made easy

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

What is Traefik?

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:

  • Load balancing
  • HTTPS support: Traefik supports automatic HTTPS, including obtaining and renewing SSL certificates.
  • Middleware: Traefik allows you to apply middlewares to requests and responses, such as authentication, rate limiting, custom headers, redirections, or for mundane requirements like removing 'www' from the requests urls.
  • Dashboard / Api: To view the status of our networks, services, etc(Optional)

Our Project

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:

Ports

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.

Volumes

These are basically the config files we use

  • traefik.yml: The startup and main configuration
  • traefik_dyn.yml: Dynamic configuration

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.

Static configuration

Mostly is self explanatory but the key concepts to understand are are:

  • Entrypoints: In our case we define two: web and websecure, and we force to always use https by redirecting to 443 all connections.
  • Providers (this is where we tell traefik for example we are using a local docker host)
  • Certificate resolvers: We use acme (the protocol we use to issue LetsEncrypt certificates).
## 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.

Routing our services using Traefik

In the docker-compose file on each of our project we need to add a few labels and restart our containers.

Key points here:

  • 'my-app': This string is an ID name that must be unique to this project
  • entrypoints=websecure: Same as configured in our traefik.yaml
  • rule=Host: This is how Traefik will identify incoming traffic that should be redirected to this container
# 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`)"

Full project on Github

https://github.com/danielm/traefik-reverse-proxy

About
Related Posts
  • No related articles have been found, for now
Comments
The comments are closed on this section.
Hire me!

I'm currently open for new projects or join pretty much any project i may fit in, let me know!

Read about what I do, or contact me for details.