Traefik Guide 2023: A Reverse Proxy for Docker 🚥
Tags: tutorial, docker, devops, traefik
Published: 2022-04-04 08:55:22

With this Traefik tutorial, we will try to show you how to proxy sites and API in a few examples, automate getting certificates and even add some middleware (to add headers for example).

Please note that we use the hash symbol (#) in the code examples where we want to explain something.

## What is Traefik?

It’s a reverse proxy designed to work with Docker. It allows you to proxy services in containers in a very simple and declarative way. At first you might be intimidated by labels, but you will get used to it 🙂

Why Traefik and not nginx, for example? We think that Traefik is simpler to manage. It only uses docker=compose (instead of that plus nginx.conf with nginx), yet still fulfills its function.

## Create a traffic config

To begin, we should create a traffic config:

```
# traefik.yml 

 

# set log level 

log: 

  level: DEBUG 

 

# enable the dashboard with useful information 

api: 

  dashboard: true 

  insecure: true 

 

# providers: in our case that's what we proxy. 

# at first we only need the Docker, 

# here's how to proxy external services  

providers: 

  docker: 

    # here's where you specify the network to add 

    # service to get it "picked up" by the traffic 

    network: traefik 

    # turn off "auto-scraping" of containers by traffic 

    # otherwise it will try to proxy all containers 

    exposedByDefault: false 

 

# entry points are basically just ports that will access 

# to Traefik and therefore to the services it proxies 

entrypoints: 

  # this is the name of the entry point for regular http traffic, usually called 

  # http or web, but you can put anything in here 

  http: 

    # the number of entry port 

    address: :80 

    http: 

      # set up a redirect for all requests to the https entry point 

      redirections: 

        entryPoint: 

          to: https 

          scheme: https 

          permanent: true 

  # create a https entry point on port 443, usually called 

  # https or websecure 

  https: 

    address: :443 

 

# ssl certificate resolvers: this is used to get certificates for domains. 

# We have just one for now and later we will add another, called Wildcard Resolver 

certificatesResolvers: 

  simple-resolver: 

    acme: 

      # acme challenge type, we need it so that letsencript can understand that this is our 

      # domain we need to specify the entry point on which the challenge will run 

      # more info about challenges here https://letsencrypt.org/docs/challenge-types/ 

      httpchallenge: 

        entrypoint: http 

      # letsencript needs your email, it will send all sorts of information there, 

      # e.g. your certificate's about to go bad 

      email: me@example.com 

      # that's where Traefik will put the certificates, it's better to run volumetric 

      # that's what we'll do below 

      storage: /letsencrypt/acme.json 

 

accesslog: true 

```

```
# Dockerfile 

FROM traefik:v2.5.2 

 

WORKDIR /traefik 

 

COPY ./traefik.yml 

 

CMD ["traefik"] 

 

# docker-compose.yml 

 

version: "3.8" 

 

services: 

  traefik: 

    build: . 

    container_name: traefik 

    restart: always 

    ports: 

      # open ports for http, https, and dashboard of Traefik, 

      # the last one should not be exposed outside of your local network 

      # it will be accessible via ssh (see below) 

      - 80:80 

      - 443:443 

      - 127.0.0.1:8080:8080 

    volumes: 

      # traffic needs access to docker.sock to monitor the containers 

      - /var/run/docker.sock:/var/run/docker.sock:ro 

     # and here is the volumetric access to the certificates 

      - /data/letsencrypt:/letsencrypt 

    networks: 

      - traefik 

 

  # for the sake of example let's connect whoami, a simple service that displays 

  # information about the request in textual form 

  whoami: 

    image: "traefik/whoami" 

    restart: always 

    labels: 

      # enable Traefik for this container 

      - traefik.enable=true 

      # set Traefik network 

      - traefik.docker.network=traefik 

      # here is the fun part: adding a router and a rule for it 

      # in this case the router will be named whoami 

      # and will be available at example.com 

      # be sure to add the name of the router, it has to be 

      # be unique, in our case it is whoami (comes after 

      # traefik.http.routers.) 

      - traefik.http.routers.whoami.rule=Host(`example.com`) 

      # Set through which entry point the router will be accessible 

      - traefik.http.routers.whoami.entrypoints=https 

      # set certresolver 

      - traefik.http.routers.whoami.tls.certresolver=simple-resolver 

      # you don't actually have to specify the port explicitly 

      # traefik is able to figure out which port the service is listening on, 

      # It might happen that one container listens to several ports at the same time. 

      port listens to several # ports (e.g. rabbitMq does this), then you will 

      # to create several routers and specify explicitly several ports 

      - traefik.http.services.whoami.loadbalancer.server.port=80 

    networks: 

      - traefik 

 

# and the networks 

networks: 

  traefik: 

    external: 

      name: traefik 
```

That’s it, now you can run it and be happy that you did.

If you want to poke the dashboard, you can do so by forwarding ports via ssh

_ssh -L 8080:localhost:8080 root@example.com_

and open _localhost:8080_ in the browser

![Traefik dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cqvwp9hjm438lrarnmm.png)

## Proxying external services

You know what this Traefik tutorial lacks? Information on external services!

Traefik can be used not only for services in Docker, but also for external services. It supports load balancing out of the box, i.e. if you have replicated service, you just specify all hosts and Traefik will do the rest. 

To proxy external services (outside the Docker network) you need to add provider in traefik.yml

```
# traefik.yml 

 

# ... 

 

providers: 

  docker: 

    network: traefik 

    exposedbydefault: false 

 

  # add a file provider that will pull in data from 

  # directory external 

  file: 

    directory: ./external 
```

To proxy services on the local network, you must add a docker-host service, because localhost inside the container will point to the network of the container itself, not to the local network of the machine

```
# docker-compose.yml 

 

version: "3.8" 

 

services: 

  # ... 

  traefik: 

    # ... 

    networks: 

      - traefik 

      # add a shared network for the dockerhost and Traefik 

      - local 

 

 

  docker-host: 

    image: qoomon/docker-host 

    cap_add: [ "NET_ADMIN", "NET_RAW" ] 

    restart: always 

    networks: 

      - local 

 

# ... 

 

networks: 

  traefik: 

    external: 

      name: traefik 

  local: 
```

```
# Dockerfile 

 

FROM traefik:v2.5.2 

 

WORKDIR /traefik 

 

COPY ./traefik.yml 

# copy the folder with the external service configs 

COPY ./external 

 

CMD ["traefik"] 
```

And also the config of the external service itself (place all configs in the external directory).

```
# external/example.yml 

http: 

  services: 

    example-api: 

      loadBalancer: 

        servers: 

         # if the service is on an external host, 

         # we simply write ip or domain 

          - url: "http://123.456.789.123:4716" 

    example-web-client: 

      loadBalancer: 

        servers: 

         # if it’s on localhost, then type in docker-host 

          - url: "http://docker-host:8132" 

 

  routers: 

    example-web-client: 

      entryPoints: 

        - https 

      # the web client will be accessible via any paths on the domain 

      # web.example.com 

      rule: "Host(`site.example.com`)" 

      service: example-web-client 

      tls: 

        certResolver: simple-resolver 

    example-api: 

      entryPoints: 

        - https 

      # the api will only be available at site.example.com/api(.*) 

      # no need to add any additional rules for the webserver 

      # Traefik will route requests to /api, 

      # this works just like a css specificity 

      rule: "Host(`site.example.com`) && PathPrefix(`/api`)" 

      service: example-api 

      tls: 

        certResolver: simple-resolver 
```

## Wildcard Certificates

Traefik can do this too! Let’s rewrite docker-compose.yml so that whoami is accessible by *.example.com.

First, we have to add wildcard-resolver to the traffic config.

```
# traefik.yml 

 

certificatesResolvers: 

  # ... 

  wildcard-resolver: 

    acme: 

      dnschallenge: 

        # specify the dns provider, in this example it would be godaddy, 

        # but Traefik knows how to work with others: 

        # https://doc.traefik.io/traefik/https/acme/#dnschallenge 

        provider: godaddy 

      email: me@example.com 

      storage: /letsencrypt/acme.jso 
```

```
# docker-compose.yml 

 

version: "3.8" 

 

services: 

  traefik: 

    build: ./proxy 

    container_name: traefik 

    restart: always 

    environment: 

      # specify the api keys of our provider from the environment variables 

      - GODADDY_API_KEY=${GODADDY_API_KEY} 

      - GODADDY_API_SECRET=${GODADDY_API_SECRET} 

      - GODADDY_POLLING_INTERVAL=10 

      - GODADDY_PROPAGATION_TIMEOUT=300 

    ports: 

      - 80:80 

      - 443:443 

      - 127.0.0.1:8080:8080 

    volumes: 

      - /var/run/docker.sock:/var/run/docker.sock:ro 

      - /data/letsencrypt:/letsencrypt 

    labels: 

      - traefik.enable=true 

      - traefik.http.routers.api.entrypoints=http 

    networks: 

      - local 

      - traefik 

 

  whoami: 

    image: "traefik/whoami" 

    restart: always 

    labels: 

      - traefik.enable=true 

      - traefik.docker.network=traefik 

     # change the rules for the router 

      - traefik.http.routers.whoami.rule="Host(`example.com`) || HostRegexp(`{subdomain:.+}.example.com`)" 

      - traefik.http.routers.whoami.entrypoints=https 

     # set wildcard-resolver 

      - traefik.http.routers.whoami.tls.certresolver=wildcard-resolver 

     # domains on which the resolver will receive the certificates 

      - traefik.http.routers.whoami.tls.domains[1].main=example.com 

      - traefik.http.routers.whoami.tls.domains[1].sans=*.example.com 

      - traefik.http.services.whoami.loadbalancer.server.port=80 

 

    networks: 

      - traefik 

 

    # ... 
```

## Middlewares

Traefik allows you to create middleware and apply it on routers and even entry points!

For example, if you need to remove some service from search results, you can always just attach X-Robots-Tag: noindex, nofollow.

```
# docker-compose.yml 

 

# ... 

  whoami: 

    image: "traefik/whoami" 

    reboot: always 

    labels: 

      - traefik.enable=true 

      - traefik.docker.network=traefik 

      - traefik.http.routers.whoami.rule="Host(`example.com`) || HostRegexp(`{subdomain:.+}.example.com`)" 

      - traefik.http.routers.whoami.entrypoints=https 

      - traefik.http.routers.whoami.tls.certresolver=wildcard-resolver 

      - traefik.http.routers.whoami.tls.domains[1].main=example.com 

      - traefik.http.routers.whoami.tls.domains[1].sans=*.example.com 

      - traefik.http.services.whoami.loadbalancer.server.port=80 

      # Creating a middle-point software where 

      # noindex is a title 

      # headers are middleware types 

      - "traefik.http.middlewares.noindex.headers.customresponseheaders.X-Robots-Tag=noindex, nofollow" 

      # Adding our middleware to the router. 

      - traefik.http.routers.whoami.middlewares=noindex@docker 

```

You can have a number of middleware attached to your router, in which case they must be specified, separated by commas.

– “traefik.http.routers.whoami.middlewares=noindex@docker, something@docker, example@file”

Middlewares can be also applied not only to routers, but also on entire entry points. In that case you create a middleware in labels anyway, you can do it in Traefik itself.

```
# docker-compose.yml 

 

# ... 

 

  traefik: 

    # ... 

    labels: 

      - "traefik.enable=true" 

      - "traefik.docker.network=traefik" 

      - "traefik.http.routers.api.entrypoints=http" 

      - _traefik.http.middlewares.noindex.headers.customresponseheaders.X-Robots-Tag=noindex, nofollow_

 

# ... 

 

And add in middleware traefik.yml to the entrypoint 

# traefik.yml 

 

# ... 

 

entrypoints: 

  http: 

    address: :80 

    http: 

      redirections: 

        entryPoint: 

          to: https 

          scheme: https 

          permanent: true 

  https: 

    address: :443 

    # add http middleware 

    http: 

      middlewares: 

        - "noindex@docker" 

 

# ... 
```

## Conclusion

This is our short tutorial on Traefik. We hope you learned something new or at least grasped the scope of how great and multi-functional Traefik is. We could be going on and on about Traefik but it’s better if you go and read their [official documentation](https://doc.traefik.io/traefik/middlewares/overview/) 🙂