How to setup Traefik v2 with automatic Let’s Encrypt certificate resolver
Tags: docker, programming, tutorial, beginners
Published: 2022-10-24 15:15:25

[Paul Knulst](https://www.paulsblog.dev/)  in  [Docker](https://www.paulsblog.dev/tag/docker/) • Nov 14, 2021 • 3 min read

* * *


Today it is really important to have SSL-encrypted websites. This guide will show how easy it is to have an automatic SSL resolver built into your traefik load balancer.

**[After I learned how to docker](https://www.paulsblog.dev/personal-experience-with-docker/)**, the next thing I needed was a service to help me organize my websites. This is why I learned about [traefik](https://traefik.io/) which is a:

> __Cloud-Native Networking Stack That Just Works__

One important feature of __traefik__ is the ability to create [Let’s Encrypt](https://letsencrypt.org/) SSL certificates automatically for every domain which is managed by __traefik__.

Then I started to research…

| ![https://www.paulsblog.dev/how-to-setup-traefik-with-automatic-letsencrypt-certificate-resolver](https://www.paulsblog.dev/content/images/2022/09/image--2-.webp)  |
|:--:|
|<center>*Me sitting in front of my computer researching*</center> |

I tested several configurations and created my own __traefik__ instances on my local machine until I came up with this docker-compose.yml:

```yaml
version: "3.3"
services:
  traefik:
    image: "traefik:v2.2.1"
    container_name: traefik
    hostname: traefik
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker
      - --providers.docker.exposedByDefault=false
      - --api
      - --certificatesresolvers.le.acme.email=${TRAEFIK_SSLEMAIL?Variable not set}
      - --certificatesresolvers.le.acme.storage=./acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./acme.json:/acme.json"
    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`dashboard.${PRIMARY_DOMAIN}`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=le"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.middlewares=authtraefik"
      - "traefik.http.middlewares.authtraefik.basicauth.users=devAdmin:$2y$05$h9OxLeY20/5uiXjfPgdRxuFlrfqBf2QifYDgrwsR6rAEgX3/dpOGq" # user:devAdmin, password:devto
      # global redirect to https
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      # middleware redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    restart: unless-stopped
    networks:
      - traefik-public
  my-app:
    image: containous/whoami:v1.3.0
    hostname: whoami
    container_name: whoami
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.my-app.rule=Host(`whoami.${PRIMARY_DOMAIN}`)"
      - "traefik.http.routers.my-app.middlewares=auth"
      - "traefik.http.routers.my-app.entrypoints=websecure"
      - "traefik.http.routers.my-app.tls=true"
      - "traefik.http.routers.my-app.tls.certresolver=le"
      - "traefik.http.middlewares.auth.basicauth.users=devAdmin:$2y$05$h9OxLeY20/5uiXjfPgdRxuFlrfqBf2QifYDgrwsR6rAEgX3/dpOGq" # user:devAdmin, password:devto
    networks:
      - traefik-public:
networks:
  traefik-public:
    external: true
```

This file contains **several important sections:**

1.  Two entry points `web` (**__Line 8__**) and `websecure` (**__Line 9__**) which are used for `http` and `https`
2.  Enabling docker (**__Line 10__**) but not publishing every container by default (**__Line 11__**)
3.  Activate API (with URL defined in labels) (**__Line 12__**)
4.  Certificate handling. Defining an info email (**__Line 13__**), set a storage `acme.json` (**__Line 14__**), activating TLS (****__Line 15__**)
5.  Exposing port for HTTP (**__Line 17__**) and HTTPS (**__Line 18__**)
6.  Within the volumes section, the docker-socket will be mounted into `****traefik****` container (**__Line 20__**) and the `acme.json` is mounted into the local filesystem (**__Line 21__**)
7.  Enable `traefik` for this service (**__Line 23__**). This has to be done because no service is exported by default (__see Line 11__)
8.  Add the dashboard domain (__**Line 25**__), define a service (__**Line 26**__), activate TLS (__**Line 27**__) with a prior defined certificate resolver (__**Line 28**__), and set the `websecure` entry point (__**Line 29**__)
9.  Activate __HTTP - Basic Auth__ middleware (**__Line 30__**)which will be “__created__” in the next line
10.  Creating the `**traefik**` dashboard which is encrypted with __HTTP - Basic Auth__ (**__Line 31__**)
11.  Global redirect to HTTPS is defined and activation of the middleware (**__Line 32 - 37__**)
12.  To test I defined another service `**whoami**` just to show some data and test the **SSL certificate** creation (**__Line 41 - Line 55__**)

**Before** running the docker-compose.yml a network **has to be created**! This is necessary because within the file **an external network is used (Line 56–58)**. This is important because the external network `traefik-public` will be used between different services.

The external network is created with:
```bash
docker network create traefik-public
```

The last step is exporting the needed variables and running the `docker-compose.yml`:
```bash
export PRIMARY_DOMAIN=yourdomain.de
export TRAEFIK_SSLEMAIL=youremai@yourdomain.de
    
docker-compose up -d
```

The commands above will now create two new subdomains (https://dashboard.yourdomain.de and https://whoami.yourdomain.de) which also use an **SSL** certificate **provided by Let’s Encrypt**

| ![Finally finish setting up the Traefik v2 within your Docker environment](https://www.paulsblog.dev/content/images/2022/09/eden-constantino-32aK4c8Iekc-unsplash--2-.webp) |
|:--:|
|<center>*Photo by [Eden Constantino](https://unsplash.com/@edenconstantin0?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit) / [Unsplash](https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit)*</center>|

Closing Notes
-------------

I hope this article gave you a quick and neat overview of how to set up __traefik__

Code-wise a lot of improvements can be made. However, with the current very limited functionality it is enough. It is more about customizing new commands, but always focusing on the least amount of sources for the truth.

Happy Dockering! 🥳 👨🏻‍💻

This article was published on my blog at [https://www.paulsblog.dev/how-to-setup-traefik-with-automatic-letsencrypt-certificate-resolver/](https://www.paulsblog.dev/how-to-setup-traefik-with-automatic-letsencrypt-certificate-resolver/)

Feel free to connect with me on [my personal blog](https://www.paulsblog.dev) [Medium](https://medium.knulst.de), [LinkedIn](https://www.linkedin.com/in/paulknulst/), and [Twitter](https://twitter.com/paulknulst).

* * *

Did you find this article valuable? Want to support the author? (... and support development of current and future tutorials!). You can sponsor me on [Buy Me a Coffee](https://buymeacoffee.com/paulknulst) or [Ko-Fi](https://ko-fi.com/paulknulst). Furthermore, you can become a free or paid member by [signing up on this website](https://www.paulsblog.dev/#/portal). See the [contribute page](https://www.paulsblog.dev/contribute/) for all (free or paid) ways to say thank you!

* * *

Photo by author - Illustration by author of components used to achieve the goal