Traefik Container mit https und Let's Encrypt

Ich bin mir noch nicht sicher, ob ich im Strahl kotzen möchte oder die Möglichkeiten des Modules bewundern soll. Es geht um den Docker Container Traefik🖹 zusammen mit Let's Encrypt🖹.

Es läuft so ziemlich direkt wenn man es einfach einbindet und da hinter ein paar normale Port 80 Webserver hat. Aber das ist wohl nichts, was man wirklich wollen sollte.

Die Doku vom Traefik selbst ist - naja sagen wir - unfangreich, kompakt und kompliziert. Und die Quellen für Lösungen sind alle unterschiedlich.

Eigens traefik.yml

Im ersten Schritt ersetze ich deshalb das globale Konfig File durch mein eigenes:

 1global:
 2  checkNewVersion: true
 3  sendAnonymousUsage: false
 4
 5providers:
 6  docker:
 7    endpoint: "unix:///var/run/docker.sock"    
 8    exposedByDefault: false
 9    swarmMode: false
10    network: web
11
12api:
13  insecure: false
14
15entryPoints:
16  web:
17    address: :80
18
19  websecure:
20    address: :443
21
22certificatesResolvers:
23  leresolver-prod:
24    acme:
25      email: XXXXXXXXXXXXXX
26      storage: /etc/traefik/acme/acme.json
27      tlsChallenge: {}
28
29  leresolver-dev:
30    acme:
31      email: XXXXXXXXXXXXXX
32      storage: /etc/traefik/acme/acme-stage.json
33      tlsChallenge: {}
34      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"

Wichtig war mir dabei:

  • exposedByDefault auf false
  • 2 unterschiedliche Let's Encrypt Resolver leresolver-prod und leresolver-dev
  • der Storage Pfad zum acme.json, so dass dieses auf ein Volume kann

Jetzt wird es sogar einfach, hier der Ausschnitt aus dem Docker Compose zum Start des Traefik Proxies:

 1service:
 2  proxy:
 3    image: traefik:latest   
 4    restart: always
 5    ports:
 6      - "80:80"
 7      - "443:443"
 8    networks:
 9      - web
10    volumes:
11      - type: bind
12        source: /var/run/docker.sock
13        target: /var/run/docker.sock
14      - acme:/etc/traefik/acme
15      - /root/traefik.yml:/etc/traefik/traefik.yml
16volumes:
17  acme:

Web-Server einbinden

Und zuletzt der komplizierte Teil mit dem Web-Server, https und sogar redirect von http auf https:

 1service:
 2  www:
 3    image: mywww:latest   
 4    restart: always
 5    networks:
 6      - web
 7    labels:
 8      - traefik.enable=true
 9      - traefik.http.routers.www.rule=Host(`www.js-home.org`)
10      - traefik.http.routers.wwws.rule=Host(`www.js-home.org`)
11      - traefik.http.services.wwws.loadbalancer.server.port=80
12      - traefik.http.routers.www.entrypoints=web
13      - traefik.http.routers.wwws.entrypoints=websecure
14      - traefik.http.routers.wwws.tls=true
15      - traefik.http.routers.wwws.tls.certresolver=leresolver-prod
16      - "traefik.http.routers.wwws.tls.domains[0].main=www.js-home.org"
17      - traefik.http.routers.www.middlewares=redirect-to-https
18      - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
19      - traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
20    volumes:
21      - apache-logs:/logs
22volumes:
23  apache-logs:

Gehen wir die Labels zeilenweise durch, denn die sind hier relevant:

1traefik.enable = true

Da im traefik.yml Konfigfile global exposedByDefault abgeschaltet ist, muss nun explizit jeder Service/Container für Traefik aktiviert werden. Das ist sauberer und bringt nicht aus Versehen einen Service online.

1traefik.http.routers.www.rule = Host(`www.js-home.org`)
2traefik.http.routers.wwws.rule = Host(`www.js-home.org`)
3traefik.http.services.wwws.loadbalancer.server.port = 80

Wird wegen der http nach https Umleitungsmagie benötigt. Es wird für einen Router "www" und einen Router "wwws" die Rule zum Hostname gesetzt. Einen Port sollte man auch setzen, Port 80. Würde zwar automatisch gesetzt, aber falls mal ein anderer Port benötigt wird, dann steht das schonmal dort.

Der Servicename "wwws" ist passend zum Router "wwws" gesetzt.

Grundsätzlich sind aber die Namen frei zu vergeben, solange sie zusammen passen und (vermutlich) eindeutig für die eine Traefik Instanz sind.

1traefik.http.routers.www.entrypoints = web
2traefik.http.routers.wwws.entrypoints = websecure

So weiß Traefik, welche Entrypoints es auf traefik.yml für die beiden Router "www" und "wwws" nutzen soll, eben "web" (Port 80) und "websecure" (Port 443). Hat man nur einen Router kann man sich diese Angabe sparen, dann macht das Traefik selbst.

1traefik.http.routers.wwws.tls = true
2traefik.http.routers.wwws.tls.certresolver = leresolver-prod
3traefik.http.routers.wwws.tls.domains[0].main = www.js-home.org

Jetzt wird es spannend für HTTPS/TSL: Das wird für den Router "wwws" aktiviert und der certresolver leresolver-prod aus traefik.yml gewählt. Ich habe in dem Konfigfile 2 Stück definiert, leresolver-prod und leresolver-dev. Let's Encrypt bietet das Staging API 1 um seinen Server zu testen bevor es ein echtes Zertifikat gibt. D.h. zu Anfang, bis alles läuft, sollte man hier leresolver-dev setzen um nicht in ein Rate-Limit zu laufen und dadurch Fehler beim Testen zu bekommen.

Anführungszeichen sind bei solche Labelnamen wohl nötig, fehlen hier aber absichtlich.

1traefik.http.middlewares.redirect-to-https.redirectscheme.scheme = https
2traefik.http.middlewares.redirect-to-https.redirectscheme.permanent = true
3traefik.http.routers.www.middlewares = redirect-to-https

Und hier liegt die Magie des Redirect von http auf https und was keine Doku so richtig erklären wollte (die Reihenfolge ist übrigens egal, deshalb hier jetzt anders als oben):

Es wird eine Middleware "redirect-to-https" definiert (das ist erstmal nur ein Name, völlig egal welcher). Wichtig ist das scheme und permanent 2. Es besagt so, dass alles zu https umgeleitet werden soll.

Es wird im Router "www" die Liste der Middlewares festgelegt, also "redirect-to-https".

Fertig!

(wäre es einfach, könnte es jeder!)

siehe auch