Skip to main content

Deploy Traefik with Docker

Updated Feb 05, 2023 ·

Overview

This lab shows how to deploy Traefik using Docker Compose and test its automatic service discovery and routing.

  • Deploy Traefik as a Docker container
  • Add a simple service called "Whoami"
  • See how Traefik detects and routes traffic automatically

Lab Environment

Before starting, ensure you have the following tools installed:

If you're using Windows, make sure to switch Docker to use Linux containers after installation. This is required for compatibility with the labs. See

Use Browser-Based Docker (Optional)

If Docker doesn’t work on your machine, try the web-based option:

  • Visit Play with Docker
  • It lets you run Docker in your browser
  • You can still follow the labs, although with some limitations

This option is a good backup when local setup isn’t possible.

Clone the Repository

To try out the examples in the succeeding sections, clone the project repository from GitHub.

Clone and move into the project directory:

git clone https://github.com/joseeden/labs-traefik.git 
cd labs-traefik/01-overview

Start with Traefik

Deploy the Traefik container using a Docker Compose file.

  • Use Docker Compose to define and run Traefik
  • Enable the Traefik dashboard
  • Mount Docker socket so Traefik can monitor container events

Here's a sample docker-compose.yml snippet:

version: '3'

services:
traefik:
image: traefik:v2.3
command:
- --api.insecure=true # Enables the Traefik Dashboard
- --providers.docker=true
- --log.level=INFO
- "--entrypoints.web.address=:80"
ports:
- "80:80" # Exposes port 80 for incoming web requests
- "8080:8080" # The Web UI port http://0.0.0.0:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Allow Traefik to listen on Docker events

Run the following to start Traefik and run it in the background:

docker compose up -d

Output:

[+] Running 5/5
✔ traefik Pulled 14.1s
✔ 0a6724ff3fcd Pull complete 2.6s
✔ 64d0c2f48fed Pull complete 3.6s
✔ 00390834f324 Pull complete 8.7s
✔ 059f159f3940 Pull complete 8.8s
[+] Running 2/2
✔ Network 01-overview_default Created 0.1s
✔ Container 01-overview-traefik-1 Started

Check that it's running:

docker compose ps

Output:

NAME                    IMAGE          COMMAND                  SERVICE   CREATED              STATUS              PORTS
01-overview-traefik-1 traefik:v2.3 "/entrypoint.sh --ap…" traefik About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp

Review the logs:

docker compose logs traefik

You should see logs showing that Traefik started, loaded configuration, and is watching Docker for new containers.

traefik-1  | time="2022-08-02T21:10:13Z" level=info msg="Configuration loaded from flags."
traefik-1 | time="2022-08-02T21:10:13Z" level=info msg="Traefik version 2.3.7 built on 2021-01-11T18:03:02Z"
traefik-1 | time="2022-08-02T21:10:13Z" level=info msg="\nStats collection is disabled.\nHelp us improve Traefik by turning this feature on :)\nMore details on: https://doc.traefik.io/traefik/contributing/data-collection/\n"
traefik-1 | time="2022-08-02T21:10:13Z" level=info msg="Starting provider aggregator.ProviderAggregator {}"
traefik-1 | time="2022-08-02T21:10:13Z" level=info msg="Starting provider *traefik.Provider {}"
traefik-1 | time="2022-08-02T21:10:13Z" level=info msg="Starting provider *docker.Provider {\"watch\":true,\"endpoint\":\"unix:///var/run/docker.sock\",\"defaultRule\":\"Host(`{{ normalize .Name }}`)\",\"exposedByDefault\":true,\"swarmModeRefreshSeconds\":15000000000}"

Add the “Whoami” Service

Add a basic test service that prints connection info for confirming Traefik’s routing.

  • Add a “Whoami” container
  • Apply a label so Traefik knows how to route traffic
  • Access it through a browser or terminal

Add this section in your compose file:

  whoami:
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
info

Traefik uses labels to discover and configure routing automatically. This makes it powerful and flexible for containerized apps.

The docker-compose.yml should now look like this:

version: "3"

services:
traefik:
image: traefik:v2.3
command:
- --api.insecure=true # Enables the Traefik Dashboard
- --providers.docker=true
- --log.level=INFO
- "--entrypoints.web.address=:80"
ports:
- "80:80" # Exposes port 80 for incoming web requests
- "8080:8080" # The Web UI port http://0.0.0.0:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Allow Traefik to listen on Docker events

whoami:
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

Then restart the deployment:

docker compose up -d

Check the services again:

docker compose ps

You should now see both services are running:

NAME                    IMAGE               COMMAND                  SERVICE   CREATED          STATUS          PORTS
01-overview-traefik-1 traefik:v2.3 "/entrypoint.sh --ap…" traefik 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
01-overview-whoami-1 containous/whoami "/whoami" whoami 54 seconds ago Up 54 seconds 80/tcp

Now open your browser and go to:

http://whoami.docker.localhost

You should see a response showing network info from the Whoami container. This means Traefik saw the container, picked up its routing rule, and sent traffic to it correctly.

Hostname: 91bdfc0231fe  
IP: 127.0.0.1
IP: 172.20.5.12
RemoteAddr: 172.18.0.1:50314
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
X-Real-Ip: 172.18.0.1
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 42efc1a512b3

Test with Curl

You can also test it from the terminal:

curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Expected output:

Hostname: 91bdfc0231fe  
IP: 127.0.0.1
IP: ::1
IP: 172.20.5.12
RemoteAddr: 172.18.0.1:50314
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
X-Real-Ip: 172.18.0.1
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 42efc1a512b3

This shows the same response you’d get in a browser, proving that routing works with host-based rules.

NOTE: If you are using WSL, you may get a 404 page not found error when you try to curl the host. This is because in WSL, the localhost refers to WSL itself, not the Windows host where Traefik is listening.

Test it in Powershell using the same command:

curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Scaling and Loadbalancing

Now that Traefik is detecting services and routing requests, the next step is to scale the whoami service.

  • Scale the service by adding more containers
  • Uses round-robin for loadbalancing by default
  • See all traffic visually on the Traefik dashboard

Verify the services first:

$ docker compose ps

NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
01-overview-traefik-1 traefik:v2.3 "/entrypoint.sh --ap…" traefik 14 minutes ago Up 14 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
01-overview-whoami-1 containous/whoami "/whoami" whoami 15 minutes ago Up 14 minutes 80/tcp

Scale whoami to 3 containers:

docker compose scale whoami=3 

Output:

[+] Running 3/3
✔ Container 01-overview-whoami-1 Running 0.0s
✔ Container 01-overview-whoami-3 Started 1.0s
✔ Container 01-overview-whoami-2 Started

You should now see three whoami contianers listed:

$ docker compose ps

NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
01-overview-traefik-1 traefik:v2.3 "/entrypoint.sh --ap…" traefik 15 minutes ago Up 15 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
01-overview-whoami-1 containous/whoami "/whoami" whoami 16 minutes ago Up 16 minutes 80/tcp
01-overview-whoami-2 containous/whoami "/whoami" whoami 16 seconds ago Up 16 seconds 80/tcp
01-overview-whoami-3 containous/whoami "/whoami" whoami 16 seconds ago Up 15 seconds 80/tcp

In your terminal (or Powershell), run the curl command:

> curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Hostname: a8c2f1b0e5cd
IP: 127.0.0.1
IP: ::1
IP: 172.20.5.11

If you run the curl command a few more times, you will see that it is cycling through the three whoami instances.

> curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Hostname: d3f84c78e9ab
IP: 127.0.0.1
IP: ::1
IP: 172.20.5.13
> curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Hostname: 91bdfc0231fe
IP: 127.0.0.1
IP: ::1
IP: 172.20.5.12

To scale down:

docker compose scale whoami=1

Then verify the services:

$ docker compose ps

NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
01-overview-traefik-1 traefik:v2.3 "/entrypoint.sh --ap…" traefik 20 minutes ago Up 20 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
01-overview-whoami-1 containous/whoami "/whoami" whoami 21 minutes ago Up 21 minutes 80/tcp

Traefik automatically detects when the other two whoami instances are no longer available and routes all incoming requests to the remaining container. You can confirm this by running the curl command multiple times. Each response will now display the same hostname.

curl -H "Host: whoami.docker.localhost" http://127.0.0.1

Cleanup

To remove the resources:

docker compose down