Traefik – Der etwas komplexere Reverse-Proxy
Im Juli 2023 haben wir Ihnen mit Caddy bereits einen Loadbalancer bzw. Reverse-Proxy vorgestellt, mit dem Sie Ihre Webseiten sehr einfach per https erreichbar machen und absichern können (Blogbeitrag: „Caddy: Reverse-Proxy in einfach?"). Während bei Caddy der Fokus klar auf Unkompliziertheit liegt und komplexere Aufgaben über Module realisierbar sind, ist Traefik so etwas wie sein großer Bruder. Auch wenn Traefik ebenfalls mit Plugins erweitert werden kann, bringt es gleich von Haus aus einige Funktionalitäten mit: Unter anderem eine Art Monitoring, eine API und die Möglichkeit hochkomplexe Loadbalancing-Szenarien abzubilden.
Als sogenannter „Cloud Native Application Proxy" liegt hier klar der Fokus auf der Bereitstellung von (Web-)Applikationen in Containern. Dabei ist es unter anderem genau wie bei Caddy möglich, die eigenen http-Applikationen direkt über https bereitzustellen und automatisiert Let's Encrypt-Zertifikate zu beziehen. Einer der primären Unterschiede zu Caddy ist jedoch die Möglichkeit, große Teile der Traefik-Konfiguration auf die Applikation auszulagern. Labels bieten beispielsweise die Möglichkeit, direkt in einer Applikation die gewünschte Domain festzulegen, den Zugriff über HTTP und/oder HTTPS zu steuern, Weiterleitungen einzurichten usw. Der Vorteil, der sich daraus ergibt, liegt auf der Hand: Das Hinzufügen von neuen Applikationen, die Traefik bereitstellen soll, kann auch bei einer Fehlkonfiguration nicht die Verfügbarkeit der bisherigen Anwendungen beeinflussen. Außerdem können wir mit einer klaren Rechtetrennung den Zugang zur globalen Traefik-Konfiguration beschränken.
Traefik-Architektur
Um unsere Applikationen über Traefik bereitstellen zu können, brauchen wir die folgenden vier Konfigurationselemente:
- Entrypoints
Vergleichbar mit dem Listen-Parameter in HAProxy, legen wir hier fest über welche Adresse/welches Protokoll/… unser Service erreichbar sein soll (Beispiel: https://www.ordix.de).
- Services
Die Applikation, die wir verfügbar machen wollen und wie wir diese ausliefern (Beispiel: localhost:8080)
- Routers
Leitet Requests von Entrypoints weiter an Services (ggf. mit dem Zwischenschritt Middleware)
- Middlewares
Middlewares werden verwendet, um Requests anzupassen, bevor sie an die Services weitergeleitet werden (z. B. Redirects, HTTPAuth, …)
Um das ganze einmal praktisch zu beleuchten, werden wir im Folgenden Traefik sowie zwei Web-Applikationen in Docker-Containern einrichten. Die einzigen Voraussetzungen für unser Setup sind:
- Linux Server (Wir verwenden hier zu Testzwecken eine Ubuntu 22.04 VM)
- Docker (In diesem Beispiel wird docker-ce in der Version 24.0.6-1 verwendet)
- Eine Domain, dessen A-Record auf unsere Server-IP zeigt (In diesem Beispiel: ordix.de als Platzhalter)
- Drei Sub-Domains (www.ordix.de, www2.ordix.de und traefik.ordix.de), die ebenfalls auf unsere Server-IP zeigen
Einrichtung Traefik
Unser Test-Setup wird komplett containerisiert eingerichtet. Das heißt: Auch unser Traefik-Loadbalancer wird in einem Container gestartet. Um die Möglichkeit der Trennung zwischen Applikation und Loadbalancer aufzuzeigen, pflegen wir unsere Traefik-config in /opt/docker/traefik/.
Dazu legen wir die Datei und die entsprechenden Ordner /opt/docker/traefik/docker-compose.yml mit folgendem Inhalt an:
--- version: "3.7" services: traefik: image: traefik:v2.10.5 command: - --entrypoints.http.address=:80 - --entrypoints.https.address=:443 - --providers.docker=true - --api=true - --certificatesresolvers.letsencrypt.acme.httpchallenge=true - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http - --certificatesresolvers.letsencrypt.acme.email=${EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json labels: # Redirect all HTTP traffic to HTTPS - traefik.http.routers.to-https.entrypoints=http - traefik.http.routers.to-https.middlewares=to-https - traefik.http.routers.to-https.rule=HostRegexp(`{host:.+}`) - traefik.http.middlewares.to-https.redirectscheme.scheme=https - traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`) - traefik.http.routers.traefik.entrypoints=https - traefik.http.routers.traefik.middlewares=auth - traefik.http.routers.traefik.service=api@internal - traefik.http.middlewares.auth.basicauth.users=${TRAEFIK_USER}:${TRAEFIK_PASSWORD_HASH} - traefik.http.routers.traefik.tls=true - traefik.http.routers.traefik.tls.certresolver=${CERT_RESOLVER} ports: - 80:80 - 443:443 networks: - default - traefik volumes: - ./data/letsencrypt:/letsencrypt - /var/run/docker.sock:/var/run/docker.sock:ro networks: traefik: external: true ...
Zum Zeitpunkt der Publikation dieses Artikels entspricht Traefik:v2.15 dem aktuellen Stand. Traefik v3 befindet sich aber schon in den Startlöchern.
Wir gehen ansonsten davon aus, dass unsere Leserschaft mit den Grundlagen von docker und docker-compose vertraut ist und gehen in der Folge nur auf einige „command"- und „labels"-Elemente ein.
command: - --entrypoints.http.address=:80 - --entrypoints.https.address=:443
Hier passieren zwei Dinge:
- Wir definieren zwei Entrypoints („http" und „https").
Diese sind als Namen zu verstehen (Denkbar und häufig in Tutorials zu sehen sind auch „web" und "web-secure".) und nicht etwa eine Festlegung des Protokolls.
- Traefik soll eingehend auf den Ports 80 (http) und 443 (https) lauschen.
Wer mit anderen Loadbalancern (z. B. haproxy) vertraut ist, kennt diese Entrypoints als „Frontend".
Im folgenden Abschnitt definieren wir unsere Präferenz für TLS-Zertifikate von Let's Encrypt, bestätigen die Urheberschaft unserer Domains mittels der sog. ACME HTTP Challenge und legen die Daten im Container unter /letsencrypt/acme.json ab:
command: [...] - --certificatesresolvers.letsencrypt.acme.httpchallenge=true - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http - --certificatesresolvers.letsencrypt.acme.email=${EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
Mit den „labels" definieren wir nun zunächst generelle Konfigurationsoptionen für alle unsere Services:
labels: - traefik.http.routers.to-https.entrypoints=http - traefik.http.routers.to-https.middlewares=to-https - traefik.http.routers.to-https.rule=HostRegexp(`{host:.+}`) - traefik.http.middlewares.to-https.redirectscheme.scheme=https
In dem obigen Block legen wir fest, dass eingehende http-Verbindungen für alle unsere Hosts (RegExp "{host:.+}") an die Middleware „to-https" geleitet werden sollen, die einen permanenten Redirect aller Anfragen von http zu https einrichtet.
Der nächste Block beschäftigt sich mit dem Traefik-Backend-Service, den wir zuvor als „eine Art Monitoring" bezeichnet haben:
labels: [...] - traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`) - traefik.http.routers.traefik.entrypoints=https - traefik.http.routers.traefik.middlewares=auth - traefik.http.routers.traefik.service=api@internal - traefik.http.middlewares.auth.basicauth.users=${TRAEFIK_USER}:${TRAEFIK_PASSWORD_HASH}
Dieser Backend-Service wird uns später eine praktische Übersicht aller unserer Applikationen anzeigen. Da hier aber durchaus auch Informationen gelistet sind, die wir nicht global für alle Interessenten zur Verfügung stellen möchten, haben wir hier mit der „middleware" auth eine einfache http-auth-Absicherung eingebaut.
Damit wären wir fertig mit unserer docker-compose.yml. Wir müssen auf der Kommandozeile aber noch das Docker Network "traefik" erstellen, welches wir dort referenzieren.
Dies geschieht mit docker network create traefik
.
Zu guter Letzt brauchen wir noch eine /opt/docker/traefik/.env-Datei, die unsere Variablen definiert:
DOMAIN=ordix.de EMAIL=ordix@ordix.de CERT_RESOLVER=letsencrypt TRAEFIK_USER=admin TRAEFIK_PASSWORD_HASH=$2y$05$55Xko821BVTdXNnrHG.BfulgKX.KKUorA25NlthG1eYmJKy4UkWga
Der Passwort-Hash entspricht hier übrigens dem Passwort „test2" und lässt sich zum Beispiel mit „htpasswd -nbB admin test2" generieren.
Und damit sind wir dann auch bereit, unseren neuen Loadbalancer zu starten. Die Konfiguration unserer Web-Applikationen nehmen wir später direkt in der Applikation (bzw. Ihren docker-compose-Dateien) vor.
cd /opt/docker/traefik docker compose up -d
Prüfen Sie die Erreichbarkeit des Traefik-Interfaces mit einem Aufruf von „https://traefik.$DOMAIN".
Nach Eingabe der Zugangsdaten sollten Sie ein noch recht leeres Dashboard auffinden, das aber bereits über https mit einem gültigen Let's Encrypt-Zertifikat erreichbar ist. Sollten Sie hier auf Fehler stoßen, prüfen Sie die logs mit docker compose logs
.
Webservice
Für unsere Webservices erstellen wir den Ordner „/opt/docker/webservices" und legen dort wieder eine „docker-compose.yml" an.
Als einfaches Beispiel erstellen wir hier sowohl einen nginx- als auch einen apache2-Container. Alles, was wir dafür brauchen, ist die Angabe der Images bei Docker Hub, Traefik Labels und das Traefik-Netzwerk:
--- version: "3.7" services: nginx: image: nginx:latest labels: - "traefik.enable=true" - "traefik.http.routers.example.rule=Host(`www.ordix.de`)" - "traefik.http.routers.example.entrypoints=https" - "traefik.http.routers.example.tls.certresolver=letsencrypt" - "traefik.http.services.example.loadbalancer.server.port=80" networks: - traefik apache2: image: httpd:latest labels: - "traefik.enable=true" - "traefik.http.routers.example2.rule=Host(`www2.ordix.de`)" - "traefik.http.routers.example2.entrypoints=https" - "traefik.http.routers.example2.tls.certresolver=letsencrypt" - "traefik.http.services.example2.loadbalancer.server.port=80" networks: - traefik networks: traefik: external: true ...
Die Labels sind hier denkbar einfach. Wir definieren nur die URI unter der unsere Webseite erreichbar sein soll und unter welchem Port unser Webserver lauscht (standardmäßig Port 80). Die anderen beiden Labels stellen sicher, dass unsere Webseite über https funktioniert.
Wir starten unsere beiden Webservices nun wieder wie folgt:
cd /opt/docker/webservices docker compose up -d
Der erste Aufruf unserer www.ordix.de und www2.ordix.de kann ein paar Sekunden dauern, aber die Services sind schnell erreichbar. Die TLS-Zertifikate werden automatisch von Traefik überwacht und regelmäßig getauscht. Wir müssen dafür übrigens den Traefik-Container nicht neu starten.
Fazit
Die Ersteinrichtung von Traefik erscheint im Vergleich zu Caddy wie eine Mammutaufgabe. Man muss sich zunächst mit der Verwendung von Labels auseinandersetzen und das doch recht komplexe Zusammenspiel zwischen Entrypoints, Middlewares, Routern und Services verstehen. Ist die Ersteinrichtung aber einmal abgeschlossen, ist das Anbinden neuer Services denkbar einfach: Mit einem kleinen Block an Labels liefern wir im Handumdrehen eine neue Webseite aus, die automatisiert mit einem Let's Encrypt-Zertifikat verschlüsselt ausgeliefert wird.
Natürlich beschränkt sich der Use-Case von Traefik nicht allein auf Webseiten. Traefik lässt sich auch hervorragend als Reverse-Proxy für Cloud-Anwendungen nutzen, einen bestehenden Service per Passwortabfrage abzusichern oder um einen Redirect einzurichten – um nur einige Beispiele zu nennen.
Beim Deployment neuer Anwendungen hat Traefik einen großen Vorteil: Da die Anbindung an Traefik mit Labels in der Anwendung selbst geschieht, müssen wir keine Anpassungen an unserer Traefik-Konfiguration machen. Ein defektes Deployment kann auch keine Auswirkungen auf bestehende Services oder Traefik selbst haben. Neben seiner Vielzahl an Funktionalitäten, bringt Traefik damit auch Vorteile im Bereich der Hochverfügbarkeit mit sich.
Für weitere Informationen ist die umfangreiche Traefik-Dokumentation sehr zu empfehlen.
Oder fragen Sie uns, wir helfen Ihnen gerne bei der Einrichtung oder Konfiguration Ihres Proxys.
Seminarempfehlungen
LINUX SYSTEMADMINISTRATION FÜR FORTGESCHRITTENE BS-12
Zum SeminarDOCKER UND PODMAN CONTAINER ESSENTIALS E-DOCK-01
Zum SeminarCLOUD COMPUTING ESSENTIALS CLOUD-COMP
Zum SeminarSernior Consultant bei ORDIX
Bei Updates im Blog, informieren wir per E-Mail.
Kommentare