Expose container with Traefik and Docker

Traefik is a great asset when you need to expose Docker containers and configure routing easily.

Traefik uses Docker API to expose ports and labels to configure Traefik routing itself.

All Traefik features can be used:

  • Entrypoints
  • Routers
  • Middlewares
ℹ️
To expose container ports Traefik needs access to the Docker socket. Read more at the https://docs.docker.com/engine/security/#docker-daemon-attack-surface.

Running Traefik on Docker daemon

Below is the Docker compose definition that runs the Traefik and Whoami containers.

version: "3.3"

services:

  traefik:
    image: "traefik:v3.1"
    container_name: "traefik"
    command:
      #- "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entryPoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=web"

We can see that labels used on the whoami container are:

  • traefik.enable=true
  • traefik.http.routers.whoami.rule=Host(whoami.localhost)
  • traefik.http.routers.whoami.entrypoints=web

Let's start with the latest. The latest label defines which entrypoint is used - web refers to 80 port and HTTP connections. websecure refers to the HTTPS connections.

For every container router must be defined with a unique name specified for that container -whoami in this case.

The router needs a definition of at least one rule but rules can be stacked.

Traefik will route the traffic correctly to the whoami container only if the hostname matches the whoami.localhost.

The first label enables Traefik to take whoami container into consideration.

TLS: Letsencrypt, Traefik, and Docker

TLS also can be automated via Letsencrypt. This process is automatic which is great. Instead of using nginx and glue scripts to automate the process, Traefik handles this automatically which is a big plus.

Traefik static configuration needs to be configured similarly:

providers:
  docker:
    exposedByDefault: false
  
  entrypoints:
    web:
      address: :80
      http:
        redirections:
          entryPoint:
            to: websecure
            scheme: https
            permanent: true
  
    websecure:
      address: :443
  
  certificatesResolvers:
    myresolver:
      acme:
        tlschallenge: true
        email: email@example.com
        storage: /SOME_PERSISTENT_LOCATION/acme.json
  
  api:
    insecure: true
    dashboard: true

Where email@example.com and /SOME_PERSISTENT_LOCATION/acme.json needs to be replaced with correct values for the specific environment where Traefik is running.

Next labels need to be applied to the container that needs to be exposed via TLS.

labels:
  "traefik.enable": "true"
  "traefik.http.routers.service.rule": "Host(`example.com`)"
  "traefik.http.routers.service.entrypoints": "websecure"
  "traefik.http.routers.service.tls.certresolver": "myresolver"
⚠️
Be sure to replace example.com with public domain.
⚠️
Cert resolver must be named myresolver!

A few labels configured correctly are all you need to expose containers via Traefik.