Using Traefik to develop locally with Docker (Part 1/x)

This is the first technical post on the blog, I’ve been meaning to write about this for some time. At first I wanted to explain everything on one post but I think is going to work better if we split it into smaller parts so here goes part 1 out of X.


First, what is Traefik Proxy? Traefik Proxy is an open source Edge Router that is cloud native. It’s a reverse proxy and a load balancer but the main thing about it is its configuration discovery. What this means is that it’s able to discover the configuration of your services and automatically route requests to them without having to change anything. In practice, it inverts the responsability of the configuration.

If you are used to something like Apache or Nginx, you need to edit a config file in order to add a new site (probably a virtual host), that configuration will live outside the project (unless you use .htaccess, which is not always recommended or even an option). By using Traefik, the configuration is part of the service itself, so it can be committed to your repo and it’ll already be there when new users start using the project. There is support for a bunch of providers but for this post we’ll be using only Docker. Depending on the provider used, the configuration comes on different forms, in our case, it comes in the form of labels, but we’ll look into them later, let’s begin by starting up Traefik.

Set up#

First, let’s create a folder on your location of choice.

mkdir traefik
cd traefik

I’m going to assume Docker and Docker Compose are already installed on your machine and you are somehow familiar with how it works. If not, I recommend reading up on their docs or some other basic intro to docker. I’ll try to add all needed commands here but will save some explainations for brevity’s sake.

First of all, because of the way networking works when using Docker Compose, the first thing we are going to do is create a network so all our projects can use it.

docker network create --driver=bridge --attachable --internal=false gateway

The command above creates a network called gateway which is attachable, external and uses the bridge driver.

Once that’s done, let’s create a basic docker-compose.yml file so and start defining our service:

version: "3"

    # The official docker image for Traefik, 2.9 is the latest at the time of writing
    image: traefik:v2.9
    # Tell traefik we want to use Docker as a provider
    command: --providers.docker
      # Bind port 80 so it's accesible from outside Docker
      - "80:80"
      # Mount the docker socket so traefik can see changes in docker
      - /var/run/docker.sock:/var/run/docker.sock:ro

# Make the network we created previously ("gateway") available as "default" network
    external: true
    name: gateway

I’ve tried to comment the file as much as possible but in short, we’re creating a Traefik image, telling it to use the network that was previously created (and that we called gateway), binding the pot 80 on the container to the external 80 on our machine, and mounting the Docker socket so it can be read by Traefik in order to look for changes.

Now you can run docker-compose up -d and traefik should be up and running. You can run docker-compose logs -f to make sure there are no typos on the config and that Traefik is not complaining about anything.

Test the set up#

In order to test the router, we’re going to use Traefik’s own whoami. This is an image that contains a tiny webserver which, for every request, outputs information of the HTTP request itself and the OS. Create another folder (outside of the traefik one) with another docker-compose.yml there:

version: "3"

    image: traefik/whoami
      # Enable traefik
      - "traefik.enable=true"
      # Tell traefik to route here all request which host is whoami.docker.localhost
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
    external: true
    name: gateway

If we start the image (docker-compose up -d) and try it out with curl (curl http://whoami.docker.localhost) or your browser of choice (just visit http://whoami.docker.localhost). The response should look something like this:

Hostname: b7949f4a618b
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: curl/7.86.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 5ba8a3b9813d

That’s it, from now on, if you have a project running in docker that needs to be accessed through HTTP, you can add the labels to your docker-compose.yml, that way you can have as many projects running at the same time as your machine can handle and don’t need to worry about what ports each one is using, because the only container with port 80 bound to your local 80, will be Traefik. The only thing you need to worry about is to have a different hostname/domain on each project and make sure that hostname points to localhost.

What’s next?#

For the following parts I’ll try to explain how to add an SSL cert to Traefik so we can use true HTTPS with our personal projects, how to make our own ngrok-like service so we can connect to our local services from outside (like a phone) or how to make two local projects talk to themselves.