admnwrk.systems

Traefik

Veröffentlicht: Lesedauer: 9 Min.

Docker Traefik Reverse Proxy

Updates

01.01.2026 – Übertrag von adminwerk.systems 16.05.2023 – IPv6 Beispiel korrigiert 22.05.2023 – Verbesserung der Textqualität; Erklärungen zur traefik Konfiguration 26.06.2023 – IPv6 erneut korrigiert

Vorwort

Viele Jahre arbeite ich schon an und mit Root-Servern und habe auch immer meine eigenen Maschinen am Laufen. Die Setups und Installationen haben dabei immer auch ein hohes Maß an Aufwand erzeugt, natürlich auch ein hohes Maß an Spaß und Freude. Häufig war der Grund etwas Neues zu probieren oder zu evaluieren. Eine neue Version, ein neues Tool, eine neue eigene Cloud usw.

Jetzt gibt es ja schon einige Zeit ein Tool, das Abhilfe schaffen kann: docker. Mit docker konnte ich mich aber laaaange Zeit einfach nicht anfreunden. Vom monolithischen Server, zur Serverfarm mit Cluster, zur Virtualisierung, zu Containern?

„Aber Container … Was soll der Mist? Alte Kamellen in neuen Kleidern?“
Auszug aus dem Vorwort von „Skalierbare Container-Infrastrukturen“ von Oliver Liebel

Mit ausreichend Distanz und ausreichend Zeit (hüstel) habe ich mich mittlerweile mit docker angefreundet, Informationen gesucht, nachgebaut, erweitert, ergänzt und Freundschaft geschlossen.

Ziel

Das Ziel dieser Anleitung ist die Bereitstellung eines docker Servers. D.h. ich installiere auf einem root-Server docker und docker compose. Um die Ressourcen hier entsprechend sinnvoll zu nutzen (Auslastung des Severs), stellt dieser Server dann entsprechende weitere Web-Applikationen zur Verfügung. Auf der Ziellinie kann WordPress, Redmine, Bitwarden, … installiert und betrieben werden. Es bedarf keiner aufwendigen Konfigurationen und dem Handling verschiedener Konfigurationstypen. Wenn wir uns eingespielt haben, kommt (fast) alles im gleichen Format: YML.

Server vorbereiten

Die Basis für diesen und die viele andere Artikel ist ein Root-Server. Ob dieser Bare Metal oder Virtual ist, spielt dabei keine Rolle. Meine Basis ist ein CPX21 bei HETZNER . Damit habe ich die komplette Spielwiese für unter 10 EUR in einem DSGVO-konformen RZ (bei Auswahl der entsprechenden Location). Auf dem Server läuft Ubuntu 22.04 Minimal. Schaut dass hier die aktuellste LTS läuft, 22, 24 .., Support muss es haben.

Der obige Link zu Hetzner hat einen PROMO-Code hinterlegt. Damit kann man noch ein paat EUR sparen

Um immer auf dem aktuellen Stand zu bleiben source ich docker aus den offiziellen Repository, womit docker immer auf dem aktuellen Stand gehalten werden kann. Hast Du im Nachbau dieser Anleitung Ubuntu neu installiert, sind die nachfolgenden beiden Zeilen nicht zwingend notwendig, da nichts davon installiert sein sollte.

sudo apt remove docker docker-engine docker.io containerd runc
sudo rm /etc/apt/sources.list/docker.list

Im nächsten Schritt aktualisiere ich die Paketliste und installiere den ersten Schwung notwendiger Pakete. Das Sourcen der docker Repositories (PGP-Keys installieren etc) teilt mir diesen Prozess in mehrere Schritte.

Notwendige Pakete installieren

sudo apt update && sudo apt install apt-transport-https ca-certificates curl \
     software-properties-common gnupg lsb-release apache2-utils

Offizielle Docker GPG Keys einbinden

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor \ 
          -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpgp

Repository einbinden

echo "deb [arch=$(dpkg --print-architecture) \
     signed-by=/etc/apt/keyrings/docker.gpg] \ 
     https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
     | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

docker + docker compose

Schlussendlich installiere ich die neueste Docker Engine und Docker Compose ins System

sudo apt update && sudo apt install docker-ce docker-ce-cli \
     containerd.io docker-buildx-plugin docker-compose-plugin

docker in Bootprozess einbinden

In wenigen Ausnahmefällen wird man den Schritt weglassen. Aber nach einem reboot sollte schon alles wieder mit starten. Das erledige ich durch nachfolgende Eingabe an der Shell

sudo systemctl enable docker.service && sudo systemctl enable containerd.service

Auf der docker-docs Homepage wird beschrieben, wie die Installation mit hello-world getestet werden kann. Schlecht ist das nicht, denn damit siehst Du recht schnell ob erstmal die Laufzeitumgebung passt. Ich erspare mir das aber und fahre stattdessen gleich mit dem Reverse-Proxy traefik fort. Weiterführende Informationen findet man im Internet, z.B. die Anleitung auf digitalocean. [Q]

Nacharbeiten

Um auch zielgerichtet in die Zukunft zu blicken, aktivieren wir IPv6 für docker [Q]. Wer Du dich für einen Server bei Hetzner entschieden hast, dann solltest Du dich gleich in die Console einloggen. Hier steht die IPv6, die wir direkt brauchen werden. Mit vi /etc/docker/daemon.yml legen wir die entsprechende Datei an und befüllen diese mit Inhalt.

IPv6

{
  "ipv6": true,
  "fixed-cidr-v6": "2a01:4f9::::1/64"
}

Bei fixed-cidr-v6 muss die verwendete IPv6 rein, logisch.

Ein kleiner Hinweis. Die letzte Direktive schließt nicht mit einem Komma ab. Wenn Du also nachfolgend beschriebenes Live Restore nutzen möchtest, dann nach der fixed-cidr-v6 Direktive ein Komma ergänzen und nach der live-restore Direktive weglassen.

Live Restore

Live Restore ist auch eine nette Nacharbeit. Dabei bleiben die Container am Start, auch wenn der Daemon herunterfährt, z.B. bei einem Update. Auch dieser Eintrag ergänzt die JSON in der /etc/docker/daemon.yml.

{
  "ipv6": true,
  "fixed-cidr-v6": "2a01:4f9::::1/64",
  "live-restore": true
}

traefik installieren

Einführung

Traefik ist angetreten Netzwerk-Komplexität abzubauen. In ganz kurzer Zeit hat traefik arrivierten Systemen den Rang abgelaufen. Insbesondere unter dem Aspekt im Umfeld von Microservices verrichtet der Reverse Proxy und/oder Load Balancer herausragende Dienste.

Das Prinzip: traefik

Das Prinzip: traefik

Oh mein Gott – Theoretiker schlagen wieder zu!

Einfach gesagt greift Traefik den zielgerichteten Datenverkehr aus dem Internet, via https ab und leitet diesen dann an den eigentlichen Service weiter.

Was sind die Vorteile?

Traefik ist mit allen Cluster Technologien kompatibel (zB Kubernetes, Docker, Docker Swarm, AWS, …). Der Hamster braucht dabei keine spezielle Konfiguration sondern macht dies automatisch. In der Verbindung mit docker, was ja hier Thema ist, schreibt man also eine docker-compose.yml und die Dienste verbinden sich. Die Entwickler geben hier eine ausführliche Einführung . Entscheidend, und damit macht es dann auch Spass, ist, dass traefik sich automatisch um die Zertifikate kümmert. Durch die entsprechenden Label in besagter docker-compose.yml werden die Zertifikate mit dem Hochfahren des Containers eingebunden.

Arbeitsverzeichnis(se)

Alle Container, die auf dem Server installiert werden, gefinden sich in /opt/containers. In einem eigenen Unterverzeichnis. Diesem Schema werden auch potentiell weiteren Anleitungen und Artikel folgen. Entsprechend kommt traefikin den Ordner /opt/containers/traefik/. Hier vorbereitet mit dem zugehörigen Volume für die Konfigurationen.

mkdir -p /opt/containers/traefik/data

SSL/TLS mit Certbot

Stand der Dinge, der Technik und des guten Geschmacks ist die Absicherung jeglicher Dienste mit SSL/TLS. Ergo wird im nächsten Schritt die Zertifikatsspeicher-Datei acme_letsencrypt.json im Arbeitsverzeichnis angelegt. Befüllung erfolgt automatisch.

touch /opt/containers/traefik/data/acme_letsencrypt.json
chmod 600 /opt/containers/traefik/data/acme_letsencrypt.json

traefik konfigurieren

Dazu wird erneut eine Konfigurationsdatei ins Arbeitsverzeichnis geschrieben. Mit dem Editor deiner Wahl, bei mir vi.

vi /opt/containers/traefik/data/traefik.yml

Die einzelnen Abschnitte von oben nach unten…

api:
  dashboard: true

certificatesResolvers:
  http:
    acme:
      email: "sollte-deine-e@mail-se.in"
      storage: "acme_letsencrypt.json"
      httpChallenge:
        entryPoint: http

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: "https"
          scheme: "https"
  https:
    address: ":443"

global:
  checknewversion: true
  sendanonymoususage: false

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: "proxy"
  file:
    filename: "./dynamic_conf.yml"
    watch: true
  providersThrottleDuration: 10

In der YAML wird auf die Datei dynamic_conf.yml referenziert. Auch in dieser stehen Anpassungen und Direktiven für traefik, wie die Verschlüsselungsparameter, -algorithmen, Einstellungen zur Middleware, Headern usw.

vi /opt/containers/traefik/data/dynamic_conf.yml

Der Inhalt orientiert sich an nachfolgendem Eintrag. Dabei sollte man regelmäßig die ciperSuites kontrollieren. Ab und an fallen welche raus, die nicht mehr als sicher gelten.

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384
      sniStrict: true
http:
  middlewares:
    traefikAuth:
      basicAuth:
        users:
          # gehashten Wert eingeben / enter hashed value
          - "dein-user:dein-passwort-hashwert"
    default:
      chain:
        middlewares:
          - default-security-headers
          - gzip

    secHeaders:
      chain:
        middlewares:
          - default-security-headers
          - gzip

    default-security-headers:
      headers:
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000
        customFrameOptionsValue: "SAMEORIGIN"
    gzip:
      compress: {}

In Zeile 21 der Datei sind Anpassungen vorzunehmen zur Definition eines Benutzernamen und Passwortes:

echo $(htpasswd -nb chef 'omlette-pommes-frites-mit-majo')

Den Rückgabewert wird passend eingefügt

middlewares:
    traefikAuth:
      basicAuth:
        users:
          - "chef:$apr1$BD.QzZIN$6OUwEXt5EtpxHi8gCngf/1"
    default:

traefik Container > docker-compose.yml

Fertig für TL;DR zum schnellen kopieren in die eigene Umgebung. Die Erläuterung reiche ich nach. Daher wird das nachfolgende Kapitel ein „Work in progress“ sein.

version: '3.9'
services:
  traefik:
    container_name: traefik
    image: traefik:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme_letsencrypt.json:/acme_letsencrypt.json
      - ./data/dynamic_conf.yml:/dynamic_conf.yml
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=https"
      # die passende Domain einsetzen / enter the correct domain
      - "traefik.http.routers.traefik.rule=Host(`traefik.DeineDomain.tld`)"
      - "traefik.http.routers.traefik.middlewares=traefikAuth@file,default@file"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=http"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly=true"
      - "traefik.http.services.traefik.loadbalancer.sticky.cookie.secure=true"
      - "traefik.docker.network=proxy"
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      proxy:
    hostname: traefik
    ports:
      - "80:80"
      - "443:443"

networks:
  proxy:
    name: proxy
    driver: bridge
    attachable: true

Hier ist auf die Domain zu achten. Hinweis: idealerweise zeigt ein A-Record auf die IP des Servers.

    labels:
      - "com.centurylinklabs.watchtower.enable=true"
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=https"
      - "traefik.http.routers.traefik.rule=Host(`traefik.pommesbude-mit-majo.tld`)"
      - "traefik.http.routers.traefik.middlewares=traefikAuth@file,default@file"

traefik Konfiguration verstehen

TL;DR – es folgt die blanke Theorie!

Auf alle Direktiven kann ich nicht eingehen. traefik gilt zwar als einfach, aber …. hahaha … naja, nein. Daher beschränke ich mich in dieser Anleitung, die ja das Ziel hat schnell ein Ergebnis zu liefern, auf die Anweisungen, die ich zum „Funktionieren“ brauche.

docker labels

Die labels: sind die Verbindung zwischen traefik und docker und begegnen Dir in allen Anleitungen, die auf docker + traefik aufsetzen.

Routers

Der Eintrag folgt dem Schema traefik.http.routers.<router_name>.<option>. Die <option> gibt dabei die Option an, die abweichend vom Standard geändert werden soll. Alle Referenzen gibt es in der traefik Dokumentation.

rule: gibt an, für welches spezifische Kriterium die rule (Regel) gültig sein soll (Ref.)
entrypoints: gibt an oder beschränkt den Anwendungsbereich von traefik auf bestimmte Einstiegspunkte (Ref.)
middlewares: mit middlewares werden die Anfragen verändert, bevor diese an den service weitergegeben werden. Dabei können die Anfragen, die Header modifiziert werden. Andere leiten die Anfragen um, oder fügen Authentifizierung hinzu… (Ref.1, Ref.2,)
service: das Ziel für die Anfragen (Ref.)

traefik starten

Ein integraler Bestandteil dieser Anleitung ist es, den Reverse Proxy traefik zu starten.

docker compose -f /opt/containers/traefik/docker-compose.yml up -d

Wenn richtig gemacht wurde, dann startet traefik seinen Dienst und wartet auf das „Einhaken“ weiterer Applikationen. Mit den entsprechenden labels versehen werde ich in weiteren Artikeln auch entsprechende Anwendungen einbinden. Die Quittung lass ich direkt ausgeben:

➜  ~ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                                                                      NAMES
44b8150d0309   traefik:latest   "/entrypoint.sh trae…"   8 minutes ago   Up 8 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   traefik

Um jetzt in und mit traefik zu arbeiten, hatte ich die Domain mittels A-Record eingetragen. Wenn diese URL aufgerufen wird, dann öffnet sich ein http-Auth, die ich mit der Eingabe der Benutzer/Kennwort-Kombi von hier hinter mir lasse.

traefik Dashboard

traefik Dashboard

Zusammenfassung

Ich habe in dieser Anleitung die Einrichtung von docker und die Bereitstellung von traefik als Reverse Proxy beschrieben und hier als handliche Bauanleitung zur Verfügung gestellt. Damit steht die Grundlage für weitere Anleitungen rund um docker-Container, die auf einem Server ihr Unwesen treiben. Abgesichert, administrierbar und einfach zu aktualisieren.

Womit geht es weiter?

Ich habe einige weitere, ergänzende Anleitungen erstellt, aber noch nicht auf die neue Plattform migriert. Zusammen mit neuen Anleitungen werde ich diese in absehbarer Zeit hier erneut anbieten.