## Einleitung Dieses Kapitel bietet einen Überblick über Traefik, ein Open Source Reverse Proxy und Load Balancer Tool. TEs wurde für die Kontrolle und Verwaltung des Datenverkehrs in einer verteilten Anwendungsumgebung entwickelt. Traefik arbeitet als Edge-Router, der Netzwerkverkehr von Clients empfängt und an die entsprechenden Backend-Dienste weiterleitet. Traefik ist besonders gut für den Einsatz in Container-Umgebungen geeignet und lässt sich nahtlos in Tools wie Docker, Kubernetes und andere Container-Orchestrierungssysteme integrieren. Es unterstützt verschiedene Load-Balancing-Strategien, um den Datenverkehr auf die Backend-Services zu verteilen und eine optimale Auslastung zu erreichen. Traefik bietet auch Funktionen wie SSL/TLS-Terminierung, Middleware für Funktionen wie Authentifizierung und Ratenbegrenzung, automatische Zertifikatserstellung und -erneuerung mit Let's Encrypt sowie Überwachungs- und Metrikfunktionen zur Überwachung des Zustands der Infrastruktur und des Datenverkehrs. Insgesamt ermöglicht Traefik eine effiziente Verteilung des Netzwerkverkehrs und verbessert die Skalierbarkeit, Zuverlässigkeit und Leistung von Anwendungen in einer verteilten Umgebung, was es zu einem attraktiven Tool für viele Platformen oder Entwickler macht ### Motivation Die effiziente Verteilung des Netzwerkverkehrs ist entscheidend für den reibungslosen Betrieb moderner Anwendungen. Mit dem Aufkommen von Containerisierungstechnologien und der Notwendigkeit, Anwendungen auf einer Vielzahl von Hosts und Infrastrukturen bereitzustellen, ist ein zuverlässiges und flexibles Werkzeug zur Traffic-Steuerung unerlässlich. Traefik bietet eine einfache und effektive Lösung für diese Anforderungen und ermöglicht es Entwicklern und Betreibern, den Traffic in ihrer Infrastruktur intelligent zu verteilen. Wir selber wollen auch unsere privaten Infrastrukturen umbauen und weniger "maintenancelastig" gestalten. Das Certificate-Management und die einfache Konfiguration eines neuen Dienstes ist für uns daher ausschlaggebened. ## Grundlagen ### Architektur Die Architektur von Traefik basiert auf dem Konzept der "Edge-Router". Traefik fungiert als Reverse Proxy und Load Balancer, der den Netzwerkverkehr von Clients entgegennimmt und an die entsprechenden Backend-Dienste weiterleitet. Es verwendet dynamische Konfigurationen, um die Backend-Dienste zu erkennen und den Verkehr auf der Grundlage verschiedener Algorithmen und Regeln zu verteilen. Traefik kann als eigenständige Anwendung oder als Teil einer Container-Umgebung (wie Docker Swarm oder Kubernetes) eingesetzt werden. Es kann mit verschiedenen Backend-Diensten und Lastausgleichsstrategien integriert werden, um eine skalierbare und zuverlässige Datenverkehrskontrolle zu ermöglichen. ### Wichtige Begriffe - Router: Ein Router in Traefik definiert eine Regel dafür, wie eingehender Datenverkehr an die entsprechenden Backend-Dienste weitergeleitet werden soll. Router können auf Basis von Hostnamen, Pfaden, Header-Werten und anderen Kriterien konfiguriert werden. - Middleware: Die Middleware in Traefik bietet Funktionen wie SSL/TLS-Terminierung, Rewrite-Regeln, Authentifizierung, Ratenbegrenzung und mehr. Sie können auf Router- oder Service-Ebene angewandt werden, um spezifische Verkehrsanforderungen zu erfüllen. - Service: Ein Service in Traefik stellt einen Backend-Service dar, auf den der eingehende Datenverkehr verteilt wird. Dabei kann es sich um eine einzelne Anwendung oder eine Gruppe von Anwendungen handeln, die denselben Zweck erfüllen. - Provider: Traefik unterstützt verschiedene Provider, um Informationen über Backend-Services und deren Konfigurationen zu erhalten. Beispiele für Provider sind Docker, Kubernetes, Consul, etcd und viele andere. ### Warum sollte man Traefik einsetzen? Traefik ist eine gute Wahl, wenn es um die Steuerung und das Management des Datenverkehrs in einer verteilten Anwendungsumgebung geht. Es bietet eine Reihe von Vorteilen gegenüber Alternativen wie NGINX, Apache2 oder HAProxy. Ein wichtiger Faktor ist, dass Traefik speziell für den Einsatz in Container-Umgebungen entwickelt wurde. Es lässt sich nahtlos in Tools wie Docker und Kubernetes integrieren und ermöglicht eine einfache Skalierung und Verwaltung von Anwendungen in einer Container-Umgebung. Traefik unterstützt die automatische Erkennung von Backend-Diensten und passt sich dynamisch an Veränderungen in der Umgebung an. Darüber hinaus bietet Traefik eine einfache Konfiguration. Die deklarative Konfiguration in YAML oder TOML ist leicht zu verstehen und zu verwalten. Im Vergleich dazu erfordern NGINX, Apache2 und HAProxy oft eine detailliertere und komplexere Konfiguration. Ein weiterer großer Vorteil von Traefik ist seine integrierte SSL/TLS-Unterstützung. Traefik bietet die automatische Erstellung und Erneuerung von Zertifikaten mit Let's Encrypt, was die Einrichtung der SSL/TLS-Verschlüsselung vereinfacht und die Sicherheit der Anwendung gewährleistet. Dieser Prozess ist bei den anderen genannten Tools oft zeitaufwändig und kompliziert. Traefik ermöglicht auch dynamisches Routing und Lastausgleich. Mit flexiblen Konfigurationsoptionen kann der Datenverkehr auf der Grundlage verschiedener Kriterien wie Hostnamen, Pfade und Header-Werte gesteuert werden. Dies ermöglicht eine intelligente Verteilung des Datenverkehrs auf die Backend-Dienste. Ein weiterer Vorteil ist die Unterstützung für verschiedene Provider. Traefik kann mit verschiedenen Plattformen wie Docker, Kubernetes, Consul, etcd und anderen interagieren. Dies erleichtert die Integration in bestehende Infrastrukturen und ermöglicht eine nahtlose Zusammenarbeit mit anderen Tools. Für Studenten ist Traefik ein spanndendes Tool, um verteilte Anwendungen miteinander zu verbinden und nach außen erreichbar zu machen. # Terraform verwenden Traefik wird im Normalfall in Form eines Containers installiert. Das wird auch genauer in der Versuchsdurchführung besprochen. ## Versuchsdurchführung Der Versuch wird zusätzlich zu Traefik auch das Tool CrowdSec (ähnlich zu Fail2Ban) umfassen. ### Voraussetzungen Docker und Docker Compose müssen auf dem Host installiert sein. ### Datei-/Verzeichnisstruktur Für den Traefik Stack sollte am Anfang eine Dateistruktur erstellt werden, in welcher wir dann die Konfigurationen durchführen können. ```bash $ mkdir -p /opt/containers/traefik-crowdsec-stack/{traefik,crowdsec/{config,data},config} $ cd /opt/containers/traefik-crowdsec-stack ``` Nun müssen die initialen Dateien erstellt werden und die korrekten Berechtigungen gesetzt werden. ```bash $ touch /opt/containers/traefik-crowdsec-stack/.env $ touch /opt/containers/traefik-crowdsec-stack/config/{crowdsec.env,traefik.env,traefik-crowdsec-bouncer.env} $ touch /opt/containers/traefik-crowdsec-stack/traefik/{acme_letsencrypt.json,traefik.yml,dynamic_conf.yml,tls_letsencrypt.json} $ chmod 600 /opt/containers/traefik-crowdsec-stack/traefik/{acme_letsencrypt.json,tls_letsencrypt.json} ``` Nun muss die Docker Compose Datei für den Stack erstellt werden. `nano docker-compose.yml` ```yaml version: "3.9" services: crowdsec: container_name: ${SERVICES_CROWDSEC_CONTAINER_NAME:-crowdsec} env_file: ./config/crowdsec.env hostname: ${SERVICES_CROWDSEC_HOSTNAME:-crowdsec} healthcheck: test: ["CMD", "cscli", "version"] interval: 20s timeout: 2s retries: 5 start_period: 10s image: ${SERVICES_CROWDSEC_IMAGE:-crowdsecurity/crowdsec}:${SERVICES_CROWDSEC_IMAGE_VERSION:-latest} networks: crowdsec: ipv4_address: ${SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4:-172.31.254.254} restart: unless-stopped security_opt: - no-new-privileges=true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/auth.log:/var/log/auth.log:ro - /var/log/traefik:/var/log/traefik:ro - ./crowdsec/config:/etc/crowdsec - ./crowdsec/data:/var/lib/crowdsec/data traefik: container_name: ${SERVICES_TRAEFIK_CONTAINER_NAME:-traefik} depends_on: crowdsec: condition: service_healthy env_file: ./config/traefik.env hostname: ${SERVICES_TRAEFIK_HOSTNAME:-traefik} healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 10s timeout: 1s retries: 3 start_period: 10s image: ${SERVICES_TRAEFIK_IMAGE:-traefik}:${SERVICES_TRAEFIK_IMAGE_VERSION:-2.10} labels: traefik.docker.network: proxy traefik.enable: "true" traefik.http.routers.traefik.entrypoints: websecure traefik.http.routers.traefik.middlewares: default@file traefik.http.routers.traefik.rule: Host(${SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST}) traefik.http.routers.traefik.service: api@internal traefik.http.routers.traefik.tls: "true" traefik.http.routers.traefik.tls.certresolver: http_resolver traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly: "true" traefik.http.services.traefik.loadbalancer.sticky.cookie.secure: "true" traefik.http.routers.pingweb.rule: PathPrefix(`/ping`) traefik.http.routers.pingweb.service: ping@internal traefik.http.routers.pingweb.entrypoints: websecure networks: crowdsec: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4:-172.31.254.253} proxy: ipv4_address: ${SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4:-172.30.255.254} ports: - "80:80" - "443:443" restart: unless-stopped security_opt: - no-new-privileges:true volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/log/traefik/:/var/log/traefik/ - ./traefik/traefik.yml:/traefik.yml:ro - ./traefik/acme_letsencrypt.json:/acme_letsencrypt.json - ./traefik/tls_letsencrypt.json:/tls_letsencrypt.json - ./traefik/dynamic_conf.yml:/dynamic_conf.yml traefik_crowdsec_bouncer: container_name: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_CONTAINER_NAME:-traefik_crowdsec_bouncer} depends_on: crowdsec: condition: service_healthy env_file: ./config/traefik-crowdsec-bouncer.env hostname: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME:-traefik-crowdsec-bouncer} image: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE:-fbonalair/traefik-crowdsec-bouncer}:${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE_VERSION:-latest} networks: crowdsec: ipv4_address: ${SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4:-172.31.254.252} restart: unless-stopped networks: proxy: name: ${NETWORKS_PROXY_NAME:-proxy} driver: bridge ipam: config: - subnet: ${NETWORKS_PROXY_SUBNET_IPV4:-172.30.0.0/16} attachable: true crowdsec: name: ${NETWORKS_CROWDSEC_NAME:-crowdsec} driver: bridge ipam: config: - subnet: ${NETWORKS_CROWDSEC_SUBNET_IPV4:-172.31.0.0/16} attachable: true ``` Die meisten Einstellungen, darunter Containernamen, Hostnamen, Netzwerkeinstellungen und verwendete Docker-Images, werden im nächsten Schritt über Umgebungsvariablen in einer .env-Datei definiert. `nano /opt/containers/traefik-crowdsec-stack/.env` ```yaml # Service Crowdsec SERVICES_CROWDSEC_CONTAINER_NAME=crowdsec SERVICES_CROWDSEC_HOSTNAME=crowdsec SERVICES_CROWDSEC_IMAGE=crowdsecurity/crowdsec SERVICES_CROWDSEC_IMAGE_VERSION=latest SERVICES_CROWDSEC_NETWORKS_CROWDSEC_IPV4=172.31.254.254 # Service Traefik SERVICES_TRAEFIK_CONTAINER_NAME=traefik SERVICES_TRAEFIK_HOSTNAME=traefik SERVICES_TRAEFIK_IMAGE=traefik SERVICES_TRAEFIK_IMAGE_VERSION=2.10 SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST=`traefik.dvaplaceholder.de` SERVICES_TRAEFIK_NETWORKS_CROWDSEC_IPV4=172.31.254.253 SERVICES_TRAEFIK_NETWORKS_PROXY_IPV4=172.30.255.254 # Service Traefik Crowdsec Bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_CONTAINER_NAME=traefik_crowdsec_bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_HOSTNAME=traefik-crowdsec-bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE=fbonalair/traefik-crowdsec-bouncer SERVICES_TRAEFIK_CROWDSEC_BOUNCER_IMAGE_VERSION=latest SERVICES_TRAEFIK_CROWDSEC_BOUNCER_NETWORKS_CROWDSEC_IPV4=172.31.254.252 # Netzwerkeinstellungen NETWORKS_PROXY_NAME=proxy NETWORKS_PROXY_SUBNET_IPV4=172.30.0.0/16 NETWORKS_CROWDSEC_NAME=crowdsec NETWORKS_CROWDSEC_SUBNET_IPV4=172.31.0.0/16 ``` Die einzige Zeile, die angepasst werden muss, ist SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST. Hier wird die eigene Domain für das Traefik-Dashboard definiert. Die Konfiguration in der Docker-Compose-Datei verwendet Healthchecks für Traefik und CrowdSec. Healthchecks sind praktische Funktionen, mit denen überprüft werden kann, ob ein Dienst ordnungsgemäß ausgeführt wird. Wenn ein Healthcheck fehlschlägt, weiß Docker, dass mit diesem Dienst etwas nicht stimmt und kann entsprechend reagieren. Die Healthchecks sind in diesem Zusammenhang besonders wichtig, weil sie und die Funktion depends_on es uns ermöglichen, die Reihenfolge und die Abhängigkeiten der einzelnen Dienste in unserem Stack besser zu kontrollieren. Warum verwenden wir feste IP-Adressen? Der IP-Adressbereich jedes Netzes ist festgelegt, um eine gewisse Konsistenz in unserer Einrichtungskonfiguration zu gewährleisten. Wir weisen jeder Service-Instanz in jedem Netzwerk eine bestimmte IP-Adresse zu, die am Ende des verfügbaren IP-Bereichs liegt. Auf diese Weise stellen wir sicher, dass die IP-Adressen der Dienste konstant bleiben und nicht versehentlich durch den DHCP-Dienst von Docker einem anderen Container zugewiesen werden. Dies könnte zu Adresskonflikten führen. ### Traefik Konfiguration an sich Nun wenden wir unsere Aufmerksamkeit der traefik.yml-Konfigurationsdatei zu. In dieser Datei legen wir statische Konfigurationsoptionen fest. `nano /opt/containers/traefik-crowdsec-stack/traefik/traefik.yml` ```yaml api: dashboard: true metrics: prometheus: addrouterslabels: true certificatesResolvers: http_resolver: acme: email: "rzkennung@hs-augsburg.de" storage: "acme_letsencrypt.json" httpChallenge: entryPoint: web tls_resolver: acme: tlsChallenge: true email: "rzkennung@hs-augsburg.de" storage: "tls_letsencrypt.json" entryPoints: ping: address: ":88" web: address: ":80" http: redirections: entryPoint: to: "websecure" scheme: "https" middlewares: - traefik-crowdsec-bouncer@file websecure: address: ":443" http: middlewares: - traefik-crowdsec-bouncer@file proxyProtocol: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 forwardedHeaders: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 ping: entryPoint: "ping" global: checknewversion: true sendanonymoususage: false experimental: plugins: real-ip: moduleName: github.com/Paxxs/traefik-get-real-ip version: "v1.0.2" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: "proxy" file: filename: "./dynamic_conf.yml" watch: true providersThrottleDuration: 10 log: level: "INFO" filePath: "/var/log/traefik/traefik.log" accessLog: filePath: "/var/log/traefik/access.log" bufferingSize: 100 ``` Hier muss die RZ-Kennung E-Mail Adresse gegen eine richtige E-Mail Adresse ausgetauscht werden. Nun zur "dynamischen Konfiguration" in welcher wir die TLS Optionen und header, etc. setzen ```yml 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: default: 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: {} traefik-crowdsec-bouncer: forwardauth: address: http://traefik-crowdsec-bouncer:8080/api/v1/forwardAuth trustForwardHeader: true real-ip-cf: plugin: real-ip: Proxy: - proxyHeadername: "*" realIP: Cf-Connecting-Ip OverwriteXFF: true ``` ### CrowdSec Nun ist die initiale Konfiguration von Traefik fertig. Nun widmen wir uns dem zweiten Part: Crowdsec. `nano /opt/containers/traefik-crowdsec-stack/config/crowdsec.env` ```yaml PGID="1000" COLLECTIONS="crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors crowdsecurity/postfix crowdsecurity/dovecot crowdsecurity/nginx" ``` Diese Umgebungsvariablen sind entscheidend für die Konfiguration von CrowdSec. Sie ermöglichen es, das Verhalten von CrowdSec fein abzustimmen und an die spezifischen Anforderungen deines Systems anzupassen - PGID: Dies steht für "Group ID" und bestimmt, unter welcher Gruppen-ID der CrowdSec-Prozess ausgeführt wird. In diesem Fall ist es die Gruppen-ID "1000". Die Gruppen-ID sollte mit der ID einer bestehenden Gruppe in Ihrem System übereinstimmen, die über die erforderlichen Zugriffsrechte verfügt. - COLLECTIONS: Dies ist eine Liste von sogenannten "Sammlungsnamen". Eine Sammlung in CrowdSec ist eine Gruppe von Szenarien, Parsern und Post Overflows, die einem bestimmten Zweck dienen. In diesem Fall werden die folgenden Collections verwendet: - crowdsecurity/traefik: Diese Sammlung ist speziell für die Überwachung und den Schutz von Traefik, einem modernen Reverse Proxy und Load Balancer. - crowdsecurity/http-cve: Diese Sammlung enthält Szenarien zur Erkennung bekannter Schwachstellen und Angriffe (CVEs) auf HTTP-Servern. - crowdsecurity/whitelist-good-actors: Eine Sammlung, die sicherstellt, dass bekannte "gute" Akteure nicht fälschlicherweise als bösartig erkannt werden. - crowdsecurity/postfix und crowdsecurity/dovecot: Diese beiden Sammlungen sind speziell für die Überwachung und den Schutz von Postfix- und Dovecot-Mailservern gedacht. - crowdsecurity/nginx: Eine Sammlung, die speziell für die Überwachung und den Schutz von Nginx-Webservern entwickelt wurde. Nun müssen wir einige Daten von CrowdSec generieren lassen. ```bash $ cd /opt/containers/traefik-crowdsec-stack $ docker compose up crowdsec -d && docker compose down ``` Anpassung der Acquis-Datei: `nano /opt/containers/traefik-crowdsec-stack/crowdsec/config/acquis.yaml` ```yaml filenames: - /var/log/auth.log - /var/log/syslog labels: type: syslog --- filenames: - /var/log/traefik/*.log labels: type: traefik --- ``` Im ersten Abschnitt der Konfigurationsdatei werden die Dateien auth.log und syslog zur Analyse hinzugefügt. Diesen Dateien wird die Bezeichnung "syslog" zugewiesen. Dadurch kann CrowdSec auf diese Dateien bestimmte Analysemethoden anwenden, die für Syslog-Protokolle geeignet sind. Im zweiten Abschnitt der Konfigurationsdatei fügen wir alle Protokolldateien hinzu, die sich im Verzeichnis /var/log/traefik/ befinden und deren Dateinamen mit .log enden. Wir weisen diesen Dateien die Bezeichnung "traefik" zu. Dies ermöglicht CrowdSec die Anwendung spezifischer Analysemethoden, die für traefik-Protokolle geeignet sind. #### CrowdSec und Traefik verbinden - Traefik CrowdSec Bouncer CrowdSec ist jetzt in der Lage, Protokolldateien zu analysieren und verdächtige IP-Adressen in eine Sperrliste aufzunehmen - das ist ein großer Schritt! Aber in der aktuellen Konfiguration haben wir noch keine Maßnahmen ergriffen, um potenzielle Angriffe tatsächlich zu blockieren. Das ist die Aufgabe der sogenannten "Bouncer" in CrowdSec. `nano /opt/containers/traefik-crowdsec-stack/config/traefik-crowdsec-bouncer.env` ```yaml # Access-Token damit Bouncer und CrowdSec kommunizieren können CROWDSEC_BOUNCER_API_KEY= # Hostname mit richtigem Port von CrowdSec CROWDSEC_AGENT_HOST=${SERVICES_CROWDSEC_HOSTNAME}:8080 ``` Nun muss noch der Access Token generiert werden. ```bash $ cd /opt/containers/traefik-crowdsec-stack $ docker compose up crowdsec -d $ docker compose exec -t crowdsec cscli bouncers add traefik-crowdsec-bouncer $ docker compose down ``` In der Ausgabe sollte etwas ähnliches wie folgt stehen ```bash Api key for 'traefik-crowdsec-bouncer': eeee212hojhsdfsdsdeeeee ``` Dieser Schlüssel muss nun in die .env Datei kopiert werden. `nano /opt/containers/traefik-crowdsec-stack/config/traefik-crowdsec-bouncer.env` ```yaml # Access-Token damit Bouncer und CrowdSec kommunizieren können CROWDSEC_BOUNCER_API_KEY=eeee212hojhsdfsdsdeeeee # Hostname mit richtigem Port von CrowdSec CROWDSEC_AGENT_HOST=${SERVICES_CROWDSEC_HOSTNAME}:8080 ``` Nun kann der Stack gestartet werden und die rudimentäre Konfiguration ist fertig. ```bash $ cd /opt/containers/traefik-crowdsec-stack $ docker compose up -d ``` Nach einer Zeit und einigen Aufrufen sollten wir auch erste Metriken zu den Verbindungsversuchen sehen können `docker exec crowdsec cscli metrics` ## Literaturverzeichnis - https://goneuland.de, abgerufen am 01.07.2023 - https://doc.traefik.io/traefik/, abgerufen am 01.07.2023