Use traefik & LE resolver for automatic enrolment of IONOS certificates

If you want to use Traefik as entrypoint proxy for your homelab and implement automatic certificate enrolments

Share on:  
                 

Introduction

I use traefik reverse proxy as the entrypoint for all my docker container services to have proper SSL termination. To enrol my certificates I use the development API for IONOS to solve the dns-challenge and hand it over to the resolver to request a new certificate when I create a new service.

What is covered or what is the TL;DR here ?

We use a Kubernetes Cluster to deploy KAN into it and use the ready to use AI Skills to connect our Videostream from the camera to detect vehicles.

Parts involed:

  • Portainer for the Container/Stack management
  • Traefik revers proxy
  • IONOS developer API
  • docker-compose and a bunch of services
  • local DNS redirect to docker host

What do we want to do ?

I have a bunch of services running on my docker host and want to reach these services via SSL enabled host. So for example if I want to do something in portainer I go to portainer.ddf2.de. The ddf2.de domain is a public domain registered with IONOS and used locally to provide certificates for several services hosted.

alt text

As you can see our traefik configuration have a websecure entrypoint (because we’re redirecting everything from http to https) and we have TLS infront. This will redirect to the backend service http://172.33.0.2:9000 which is the docker network and portainer port 9000.

alt text

The benefit is that you dont need to add certificates to portainer itself, all services are running in http mode and certificates are requested and stored centrally. You could also deploy your service via http in the beginning, and after testing and moving the service in production enable SSL afterwards. The traefik cert-resolver will also take care of expiration dates and request a newer version if needed, the default period is 3 months. Another big advantage is that you dont need to select a different exposed port for multiple services running on the same backend port

Implementation

We need to implement the traefik container/service itself, followed by enablement on all services we want to expose. This also means we need to remove the exposed ports on all of our container services.

How to implement

This is my docker-compose file for the traefik container, please be aware that I dont use static/dynamic configuration to avoid seperation of config files and only use labels. The only external fil is the acme.json you need to create to store certificate data.

version: "3.5"

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    command:
      - "--log.level=INFO"
      - "--log.filePath=/logs/traefik.log"
      - "--api.insecure=false"
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedByDefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls.certResolver=ionos"
      - "--certificatesResolvers.ionos.acme.email=your-mail@mail.com"
      - "--certificatesResolvers.ionos.acme.storage=/acme.json"
      - "--certificatesResolvers.ionos.acme.dnschallenge.provider=ionos"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "/home/numark1/docker/data_traefik/logs:/logs"
      - "/home/numark1/docker/data_traefik/acme.json:/acme.json"
    networks:
      - "docker_global"
    environment:
      - "IONOS_API_KEY=1234567890"
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.rule=Host(`traefik.ddf2.de`)
      - traefik.http.routers.traefik.entrypoints=websecure
      - traefik.http.routers.traefik.tls=true
      - traefik.http.routers.traefik.tls.certresolver=ionos
      - traefik.http.routers.traefik.service=api@internal
#      - traefik.http.routers.traefik.middlewares=myauth
#      - traefik.http.middlewares.myauth.basicauth.users=user:$secret
#      - traefik.http.services.traefik.loadbalancer.server.port=8080

Lets go through the different config parts:

  • image: traefik:latest => is not recommended, instead point directly to a version
  • “–api.dashboard=true” => enable the dashboard you can see in the 2nd screenshot
  • “–providers.docker=true” => enable docker provider to automatically detect new container
  • “–entrypoints.web.address=:80” => enable the http entrypoint port 80 and redirect everyhting to websecure
  • “–entrypoints.websecure.address=:443” => enable https entrypoint port 443
  • “–entrypoints.websecure.http.tls.certResolver=ionos” => assign the certResolver named ionos to the websecure entrypoint
  • “–certificatesResolvers.ionos.acme.*” ?> configuration for the cert resolver, your mail address and the storage path for the certs
  • Ports => we need to open the entrypoint ports for http (80), https (443) and dashboard (8080)
  • Volumes => we provide the docker socket, a log folder and the acme.json to store the files Check that acme.json has 0660 permission on file
  • networks => we assign a global docker network and use it for all containers
  • environment => we need to provide the API key for the DNS challenge Request API key
  • labels => these are the labels to configure a service within traefik and as we also want to expose the dashboard with proper certificate we need to set this up
  • myauth => you should secure your dashboard with username and password which is a generic htaccess protection

Enable TLS for a service

I’ve deployed the default nginx webserver and enabled traefik management via labels, this can be used on all services you want to expose.

version: '3.5'

services:
  whoami:
    image: nginxdemos/nginx-hello
    networks:
      - "docker_global"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.rule=Host(`nginx.ddf2.de`)"
      - "traefik.http.routers.nginx.entrypoints=websecure"
      - "traefik.http.routers.nginx.tls=true"
      - "traefik.http.routers.nginx.tls.certresolver=ionos"
      - "traefik.http.services.nginx.loadbalancer.server.port=8080"

networks:
  docker_global:
    external: true

When you deploy that stack/compose file, traefik gets informed via docker socket that there is a new service and it will create the route for you. What you need to tell traefik is the port the application is communicating, in this case its port 8080. You assignt the global docker network and let traefik route all traffic from http to https (websecure) and assign a host name. This hostname is later used within the certificate requested via cert resolver from IONOS.

alt text

Obviously but worth to mention, I have a local DNS entry for my domain nginx.ddf2.de which points to the docker host IP, from there it is picked up by traefik and redirected to the internal docker network.

DNS Challenge part

Every time you create a new service and cert resolver is requesting a certificate, it needs to solve the dns challenge. This is solved via TXT entry created, there are a lot of other variants you could use but dns challenge was the one working for me.

alt text
comments powered by Disqus