Traefik 2.0 Docker Container mit Lets Encrypt nutzen

Seit kurzem nutze ich Docker auch für meine lokale Entwicklung. Um die entwickelten Features schneller an Kunden / Tester zu übermitteln nutze ich für die Bereitstellung der Features/Bugfixes Traefik (bug123.shop.michahobert.de). Damit diese Domains auch mit SSL verschlüsselt werden gibt es von Traefik eine direkte Konfiguration beim hochfahren des Containers…

Traefik

Traefik sorgt als Reverse Proxy dafür das eingehende Requests an die richtigen Container weitergeleitet werden – mit seinen bereits verfügbaren Middlewares können Basic Auth, SSL und Kompression ganz einfach umgesetzt werden.

Beispiel:

Feature 245
Neues Layout eines Shopware Shops

Middlewares:
– Basic Auth (Layout soll noch nicht öffentlich erreichbar sein – Geheimprojekt!)
– SSL Verschlüsselung für Requests an externe Quelle

Url:
https://fr245.shop1.michahobert.de

Bug 45
Bugfix eines Shopware Shops

Middlewares:
– SSL Verschlüsselung für Requests an externe Quelle
– Compress Request

Url:
https://bug45.shop2.michahobert.de

CAA Problem

Wenn Ihr das ganze erstmal testen wollt, empfehle ich auch einen einfacher Service wie whomami zu starten:

version: "3.5"

services:

  traefik:
    image: "traefik:v2.0"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.mytlschallenge.acme.email=DEINEMAIL@TEST.COM"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
    ports:
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  whoami:
    image: "containous/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`test.michahobert.de`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=mytlschallenge"

und zwar wie üblich mit docker-compose – am besten ohne -d – da wir den output/debug sehen wollen:

docker-compose up
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="No default certificate, generating one"
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Creating middleware" routerName=whoami@docker serviceName=whoami-traefik middlewareName=pipelining middlewareType=Pipelining entryPointName=websecure
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Creating load-balancer" routerName=whoami@docker serviceName=whoami-traefik entryPointName=websecure
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Creating server 0 http://172.18.0.2:80" serverName=0 routerName=whoami@docker serviceName=whoami-traefik entryPointName=websecure
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Added outgoing tracing middleware whoami-traefik" entryPointName=websecure routerName=whoami@docker middlewareName=tracing middlewareType=TracingForwarder
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Creating middleware" middlewareName=traefik-internal-recovery middlewareType=Recovery entryPointName=websecure
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Try to challenge certificate for domain [test.michahobert.de] found in HostSNI rule" routerName=whoami rule="Host(`test.michahobert.de`)" providerName=mytlschallenge.acme
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="Looking for provided certificate(s) to validate [\"test.michahobert.de\"]..." providerName=mytlschallenge.acme routerName=whoami rule="Host(`test.michahobert.de`)"
traefik    | time="2019-11-03T10:27:54Z" level=debug msg="No ACME certificate generation required for domains [\"test.michahobert.de\"]." providerName=mytlschallenge.acme routerName=whoami rule="Host(`test.michahobert.de`)"
Traefik TLS true

Sieht erstmal gut aus, aber wenn wir die URL aufrufen erscheint eine Warnung dass das SSL Cert nicht vertrauenswürdig ist.

Could not find solver for: http-01; acme: Could not find solver for: dns-01

oder

traefik    | time="2019-11-03T10:51:23Z" level=debug msg="http: TLS handshake error from 46.114.2.24:11213: remote error: tls: unknown certificate"

oder

NET::ERR_CERT_AUTHORITY_INVALID
Subject: TRAEFIK DEFAULT CERT

Issuer: TRAEFIK DEFAULT CERT

Das hat damit zu tun, dass mein Hoster kein CAA unterstützt (hier eine Liste mit allen unterstützenden Providern). Ohne diesen Eintrag stellt Lets Encrypt zwar Zertifikate aus – diese sind aber nicht verifiziert.

Ihr könnt dafür einfach kostenlose Angebot von Cloudflare (nicht mehr – da der Service wohl broken ist) oder Digital Ocean (und dort auch direkt 50$ an Startguthaben sichern – aber keine Sorge der Nameserver-Service ist kostenlos) nutzen. Dort könnt Ihr dann die Einträge hinterlegen – like so:

  1. Wählt eure Domain oder Subdomain (Wildcard mit *)
  2. Authority Granted for ist in unserem Fall letsencrypt.org
  3. Tag -> Issue
  4. Flag -> 0
Digital Ocean CAA Konfiguration

Danach startet Ihr einfach euren traefik neu (docker-compose up –force-recreate) – am besten lasst mal 5-10 min verstreichen – damit die Einträge auch existieren.

HTTPS mit TLS Handshake über Lets Encrypt Zertifikat

Tipp: Lasst den debug mode und caserver am Anfang erstmal in der Konfiguration – 5-10 fehlerhafte Requests und Ihr seid für 24 Stunden bei Letsencrypt blockiert.

Finale docker-compose Datei

version: "3.5"

services:

  traefik:
    image: "traefik:v2.0"
    container_name: "traefik"
    command:
      #- "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      #- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.mytlschallenge.acme.email=DEINEMAIL@DEINEMAIL.com"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
    ports:
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  whoami:
    image: "containous/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`test.michahobert.de`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=mytlschallenge"

Fallstricke & Hinweise

Lets Encrypt hat ein Rate Limit -> „The main limit is Certificates per Registered Domain (50 per week)“ (Quelle)

Wenn Ihr kein Digital Ocean oder andere Provider nutzen wollt, könnt Ihr auch mit Zero SSL ein Zertifikat bei Hosteurope einbinden -> https://www.hosteurope.de/blog/lets-encrypt-zertifikat-erstellen/

Mehr zum Thema CAA und wie man Wildcards setzt findet Ihr hier -> https://pixelbar.be/blog/ssl-zertifikate-neuer-dns-record-caa-ab-september-2017-verpflichtend/

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.