{"id":8870,"date":"2022-05-13T18:15:42","date_gmt":"2022-05-13T16:15:42","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=8870"},"modified":"2024-12-11T13:23:19","modified_gmt":"2024-12-11T11:23:19","slug":"traefik-auf-server-raspberry-pi-installieren-und-einrichten-reverse-proxy-fuer-docker-mit-lets-encrypt-https-zertifikaten","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/traefik-auf-server-raspberry-pi-installieren-und-einrichten-reverse-proxy-fuer-docker-mit-lets-encrypt-https-zertifikaten\/","title":{"rendered":"Traefik auf Server\/Raspberry Pi installieren und einrichten: Reverse Proxy f\u00fcr Docker mit Let&#8217;s Encrypt HTTPS-Zertifikaten"},"content":{"rendered":"<p>Wer mehrere Webanwendungen auf einem Server betreiben m\u00f6chte, ben\u00f6tigt einen Reverse Proxy. Wie das Konzept in der Theorie funktioniert, habe ich in einem eigenen Beitrag ausf\u00fchrlicher erkl\u00e4rt. Hier schauen wir uns die praktische Einrichtung von Traefik an. Ob ihr dabei einen Raspberry Pi mit Raspberry Pi OS verwendet, eine lokale VM oder einen Cloudserver, spielt dabei keine Rolle. Wichtig ist, dass ihr Debian oder ein Debian-Derivat wie Ubuntu einsetzt.<\/p>\n<p><strong>Hinweis<\/strong>: Bei jedem Heimserver (egal ob Raspberry Pi oder X86) ben\u00f6tigt ihr zus\u00e4tzlich eine \u00f6ffentliche IPv4-Adresse (sofern ihr IPv4 nutzen m\u00f6chtet, was i.d.R. der Fall ist), NAT\/Firewall-Regeln in eurem Router sowie eine dynamische DNS-Adresse. Ansonsten sind eure HTTP-Dienste nicht im Internet erreichbar, was wiederum eine Voraussetzung f\u00fcr Let&#8217;s Encrypt ist.<\/p>\n<h2 class=\"wp-block-heading\">Warum Traefik und nicht Nginx, Apache &amp; co?<\/h2>\n<p>Traefik bietet verschiedene Integrationen (<a href=\"https:\/\/doc.traefik.io\/traefik\/providers\/overview\/\" title=\"Provider genannt\" target=\"_blank\" rel=\"nofollow\"><em>Provider<\/em> genannt<\/a>) f\u00fcr unter anderem Docker, Kubernetes und andere. Das vereinfacht die Konfiguration in diesen Umgebungen enorm: Man kann mit Labels festlegen, wie ein Container erreichbar sein soll. Das h\u00e4ndische Anpassen der Konfiguration in Nginx oder einem anderen Reverse Proxy entf\u00e4llt eben so wie alles was damit zusammen h\u00e4ngt, etwa der Vergabe von statischen IP-Adressen f\u00fcr die Container. Dennoch ist Traefik effizient, <a href=\"https:\/\/doc.traefik.io\/traefik\/v1.4\/benchmarks\/\" title=\"bereits in Version 1.4 wurde 85% des Durchsatzes von Nginx erreicht.\" target=\"_blank\" rel=\"nofollow\">bereits in Version 1.4 wurde 85% des Durchsatzes von Nginx erreicht.<\/a><\/p>\n<p>Zwar kann man Traefik auch alleinstehend nutzen, also v\u00f6llig ohne Docker &amp; co. Allerdings fehlen dann einige der Vorteile. Hier sollte man zudem bedenken, dass Traefik ein reiner Reverse Proxy ist. Man kann also nicht &#8211; im Gegensatz zu Apache oder Nginx &#8211; etwa statische Dateien ausliefern oder per angebundenem PHP\/Python dynamische Inhalte generieren. Daf\u00fcr ist ein eigener Container notwendig. Wer etwa statische Dateien ausliefern m\u00f6chte, ben\u00f6tigt also einen Nginx\/Apache2 Container hinter Traefik daf\u00fcr.<\/p>\n<h2 class=\"wp-block-heading\">Installation von Traefik unter Debian\/Ubuntu\/Raspberry Pi OS<\/h2>\n<p>Voraussetzung ist, dass ihr bereits <a href=\"https:\/\/u-labs.de\/portal\/docker-auf-dem-raspberry-pi-installieren-erste-container-starten-einfach-erklaert\/\" title=\"Docker auf dem Raspberry Pi installieren &amp; erste Container starten einfach erkl\u00e4rt\">Docker <\/a>und <a href=\"https:\/\/u-labs.de\/portal\/einfuehrung-das-ist-docker-compose-und-so-installierst-du-es-auf-dem-raspberry-pi\/\" title=\"Einf\u00fchrung: Das ist Docker-Compose und so installierst du es auf dem Raspberry Pi!\">Docker-Compose<\/a> installiert habt. <a href=\"https:\/\/u-labs.de\/portal\/docker-compose-v1-vs-v2-welche-version-sollte-ich-benutzen-worin-liegen-die-unterschiede\/\" title=\"Docker Compose v1 vs. v2: Welche Version sollte ich benutzen? Worin liegen die Unterschiede?\">Wir nutzen Version 2<\/a>. Beides ist auf Debian unter x86 Servern sehr \u00e4hnlich, da das Raspberry Pi OS ebenfalls darauf basiert. Ob Docker korrekt eingerichtet wurde, k\u00f6nnt ihr mit folgendem Befehl pr\u00fcfen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker compose version\nDocker version 20.10.14, build a224086<\/code><\/pre>\n<p>F\u00fcr Traefik w\u00fcrde ich einen eigenen Ordner anlegen und in der Yaml-Datei nur Traefik bereitstellen. In diesem Beispiel legen wir die Konfigurationsdateien f\u00fcr die Container in <strong>\/etc\/docker\/container<\/strong>, dies ist aber frei w\u00e4hlbar.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">mkdir -p \/etc\/docker\/container\/traefik\nvim docker-compose.yml<\/code><\/pre>\n<p>F\u00fcr Traefik w\u00fcrde ich einen eigenen Ordner anlegen und in der Yaml-Datei nur Traefik bereitstellen. Beim Image ist zu empfehlen, zumindest eine Hauptversion (oder wie hier mit Nebenversion) zu w\u00e4hlen. <a href=\"https:\/\/doc.traefik.io\/traefik\/deprecation\/releases\/\" title=\"Eine Liste der unterst\u00fctzten Versionen ist hier zu finden\" target=\"_blank\" rel=\"nofollow\">Eine Liste der unterst\u00fctzten Versionen ist hier zu finden<\/a>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">services:\n  traefik:\n    image: traefik:v2.9\n    restart: always\n    command:\n      # Experimentell, um das Dashboard ohne Zugriffsschutz aufzurufen\n      #- &quot;--api.insecure=true&quot;\n      - &quot;--providers.docker&quot;\n      - &quot;--providers.docker.exposedByDefault=false&quot;\n      - &quot;--providers.docker.network=traefik_web&quot;\n      - &quot;--entrypoints.http.address=:80&quot;\n      - &quot;--entrypoints.http.http.redirections.entrypoint.to=https&quot;\n      - &quot;--entrypoints.http.http.redirections.entrypoint.scheme=https&quot;\n      - &quot;--entrypoints.https.address=:443&quot;\n      # Vermeidet, dass wir den resolver in jedem container mit &quot;traefik.http.routers.https.tls.certresolver=le&quot; angeben muessen\n      - &quot;--entrypoints.https.http.tls.certResolver=le&quot;\n      - &quot;--certificatesresolvers.le.acme.tlschallenge=true&quot;\n      - &quot;--certificatesresolvers.le.acme.email=deine@mail.de&quot;\n      - &quot;--certificatesresolvers.le.acme.storage=\/letsencrypt\/acme.json&quot;\n    ports:\n      - &quot;80:80&quot;\n      - &quot;443:443&quot;\n      - &quot;8080:8080&quot;\n    volumes:\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock:ro\n      - .\/letsencrypt:\/letsencrypt\n    networks:\n      - web\n\nnetworks:\n  web:\n    name: traefik_web<\/code><\/pre>\n<p>Schauen wir uns die Konfigurationsdirektiven etwas n\u00e4her an:<\/p>\n<ul class=\"wp-block-list\">\n<li><strong>providers.docker.exposedbydefault=false<\/strong> legt fest, dass neue Container nicht automatisch von Traefik erreichbar gemacht werden. Sicherheitstechnisch halte ich es f\u00fcr sinnvoll, nur die gew\u00fcnschten Container freizugeben, dazu sp\u00e4ter im Beispiel mehr.<\/li>\n<li><strong>providers.docker.network=traefik_web<\/strong> ist das Standardnetzwerk, welches f\u00fcr die Kommunikation von Traefik mit dem Container des Dienstes verwendet werden. Dies vermeidet Probleme, falls der Container \u00fcber mehrere Netzwerke verf\u00fcgt &#8211; in diesem Falle wird m\u00f6glicherweise das falsche automatisiert ausgew\u00e4hlt.<\/li>\n<li><strong>entrypoints.http.address=:80<\/strong> definiert einen Einstiegspunkt namens <strong>http<\/strong> auf Port 80. In den nachfolgenden Zeilen leiten wir diesen auf einen zweiten Einstiegspunkt namens <strong>https <\/strong>um mit entsprechendem Protokoll. F\u00fcr viele Anwendungsf\u00e4lle ist das sinnvoll, wer dies nicht m\u00f6chte kann die Weiterleitung mit diesen zwei Zeilen deaktivieren.<\/li>\n<li><strong>entrypoints.https.address=:443<\/strong> wie der vorherige, nur HTTPS auf Port 443.<\/li>\n<li><strong>certificatesresolvers.le.acme.tlschallenge=true<\/strong> erm\u00f6glicht die automatische Ausstellung und Erneuerung von TLS-Zertifikaten \u00fcber den kostenfreien Dienst Let&#8217;s Encrypt. Hierzu ben\u00f6tigt der ACME-Standard eine E-Mail Adresse. In der zuletzt angegebenen Json-Datei werden alle dazu n\u00f6tigen Daten gespeichert, wie etwa das Zertifikat oder der private Schl\u00fcssel.<\/li>\n<li>Als Reverse-Proxy geben wir Port 80\/443 f\u00fcr HTTP(S) nach au\u00dfen hin frei. Port 8080 ist f\u00fcr das Dashboard, falls gew\u00fcnscht.<\/li>\n<li>In den Volumes h\u00e4ngen wir zum einen den Docker-Socket ein. Dies ist notwendig, damit Traefik die laufenden Container einsehen und entsprechende Routen anlegen kann. Zus\u00e4tzlich wird ein Unterordner <strong>letsencrypt<\/strong> erstellt und gemountet, worin die Zertifikate und Schl\u00fcssel gespeichert werden. Dementsprechend sollte dieser Ordner gut gesch\u00fctzt werden.<\/li>\n<li>Das Netzwerk <strong>web <\/strong>(erh\u00e4lt systemweit den Ordnername als Pr\u00e4fix und hei\u00dft daher <strong>traefik_web<\/strong>) soll f\u00fcr alle Container genutzt werden, die wir hinter Traefik als Reverse Proxy schalten. So k\u00f6nnen wir jene Container die mit Traefik kommunizieren m\u00fcssen von anderen trennen, die dies nicht sollen. Beispielsweise f\u00fcr eine Datenbank.<\/li>\n<\/ul>\n<p>Um das Image herunterzulagen und den Container im Hintergrund zu starten:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">docker compose up -d<\/code><\/pre>\n<p>Man kann nun den Hostname oder die IP-Adresse des Systemes im Browser aufrufen und sollte eine <strong>404 page not found<\/strong> Fehlerseite sehen. Dies ist die Standardseite von Traefik, wenn keine passende Route gefunden wurde. Durch unsere Weiterleitung ist auch diese Fehlerseite bereits mit einem automatisch erstellten HTTPS-Zertifikat versehen, ggf. erhaltet ihr noch eine Zertifikatswarnung.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-28.png\"><img loading=\"lazy\" decoding=\"async\" width=\"704\" height=\"381\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-28.png\" alt=\"\" class=\"wp-image-8874\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-28.png 704w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-28-300x162.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-28-70x38.png 70w\" sizes=\"auto, (max-width: 704px) 100vw, 704px\" \/><\/a><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">Bereitstellen eines einfachen Webserver-Containers \u00fcber Traefik<\/h2>\n<p>Damit ist Traefik bereit, um einen Container bereitzustellen. Als einfaches Beispiel-Szenario nehmen wir hier einen Nginx Webserver. Auch hier w\u00fcrde ich einen Ordner erstellen, in dem wir alle Konfigurationsdateien platzieren, etwa:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ mkdir \/etc\/docker\/container\/nginx-demo\n$ cd \/etc\/docker\/container\/nginx-demo<\/code><\/pre>\n<p>Darin wird eine <strong>docker-compose.yml<\/strong> erstellt, mit ein paar Besonderheiten:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">services:\n  nginx:\n    image: nginx:1.27\n    labels:\n      - &quot;traefik.enable=true&quot;\n      - &quot;traefik.http.routers.nginx.rule=Host(`demo.u-labs.de`)&quot;\n    networks:\n      - traefik_web\n\nnetworks:\n  traefik_web:\n    external: true<\/code><\/pre>\n<ul class=\"wp-block-list\">\n<li>In den Labels muss Traefik f\u00fcr diesen Container aktiviert werden. Das ist durch <strong>providers.docker.exposedbydefault=false<\/strong> in dessen Konfiguration notwendig. <\/li>\n<li>Das zweite Label definiert einen Router namens <strong>nginx<\/strong>. Diese Bezeichnung ist frei w\u00e4hlbar, muss aber eindeutig sein. Router leiten Anfragen auf einen bestimmten Dienst und verwenden daf\u00fcr Regeln. In diesem Beispiel gibt es nur eine Regel: Anfragen mit dem Hostname <strong>demo.u-labs.de<\/strong> (d.H. man ruft diese Domain im Browser auf), landen bei unserem Nginx-Container.<\/li>\n<li>Der Container befindet sich im Netzwerk <strong>traefik_web<\/strong>. Dieses Netzwerk haben wir zuvor in der <strong>docker-compose.yml<\/strong> von Traefik erstellt. Durch den expliziten Name wird verhindert, dass es aus dem Name des Ordners (<strong>traefik<\/strong>) und dem Netzwerk (<strong>web<\/strong>) zusammensetzt &#8211; dies w\u00e4re der Standard. So kann Traefik mit unserem Nginx-Container kommunizieren. Es ist wichtig, dieses Netzwerk als Extern zu deklarieren. Ansonsten f\u00fchlt sich Docker Compose daf\u00fcr verantwortlich und legt ein neues, lokales Netzwerk an.<\/li>\n<\/ul>\n<p>Nachdem der Container mit <strong>docker compose up -d<\/strong> gestartet wurde, kann man die konfigurierte Domain (hier <strong>demo.u-labs.de<\/strong>) im Browser aufrufen. Statt der Standard <em>404 page not found<\/em> Seite sollte <em>Welcome to nginx<\/em> erscheinen &#8211; die Standard index.html Seite von Nginx:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-29.png\"><img loading=\"lazy\" decoding=\"async\" width=\"703\" height=\"397\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-29.png\" alt=\"\" class=\"wp-image-8876\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-29.png 703w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-29-300x169.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-29-70x40.png 70w\" sizes=\"auto, (max-width: 703px) 100vw, 703px\" \/><\/a><\/figure>\n<\/div>\n<p>Wie am Schloss oben zu erkennen, wird HTTPS mit einem g\u00fcltigen Zertifikat eingesetzt. <\/p>\n<p>Mit einem einzelnen Container bietet profitieren wir noch nicht von den meisten Vorteilen, die ein Reverse Proxy bietet. Denn im vorherigen Beispiel k\u00f6nnten wir schlichtweg Nginx direkt auf Port 80\/443 freigeben, mit dem Certbot von Let&#8217;s Encrypt automatisch Zertifikate bereitstellen und k\u00f6nnten das gleiche Ergebnis ohne vorgeschalteten Traefik erreichen. Wirklich Sinn macht das erst bei mehreren Diensten. Daher wird die Installation um einen zweiten Container erg\u00e4nzt, diesmal ein Apache mit PHP.<\/p>\n<p>Im Grunde kann man f\u00fcr weitere Dienste die gleiche Vorlage benutzen und passt nur entsprechend Name des Dienstes, Image, die Regel f\u00fcr Traefik an sowie ggf. f\u00fcr den Dienst spezifische Konfigurationseinstellungen. Letzteres ist in diesem Beispiel ein Volume, in dem ich einen lokalen Ordner einh\u00e4nge. Der wird von Apache ausgeliefert.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">services:\n  apache:\n    image: php:8.1-apache\n    labels:\n      - &quot;traefik.enable=true&quot;\n      - &quot;traefik.http.routers.apache.rule=Host(`php.demo.u-labs.de`)&quot;\n    networks:\n      - traefik_web\n    volumes:\n      - .\/html:\/var\/www\/html\n\nnetworks:\n  traefik_web:\n    external: true<\/code><\/pre>\n<p>Auch das Starten ist identisch wie beim Nginx-Container. Unter der eingerichteten Domain (hier <strong>php.demo.u-labs.de<\/strong>) bekommen wir eine <em>Forbidden<\/em> Seite zu sehen:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-30.png\"><img loading=\"lazy\" decoding=\"async\" width=\"703\" height=\"331\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-30.png\" alt=\"\" class=\"wp-image-8877\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-30.png 703w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-30-300x141.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-30-70x33.png 70w\" sizes=\"auto, (max-width: 703px) 100vw, 703px\" \/><\/a><\/figure>\n<\/div>\n<p>Unten wird aber klar, dass dies von Apache ausgeliefert wird &#8211; somit sind wir nicht beim zuvor eingerichteten Nginx-Container gelandet. Der Fehler erscheint, weil keine Indexseite eingerichtet ist und der Apache standardm\u00e4\u00dfig so eingerichtet ist, in diesem Falle nicht den Inhalt des Ordners aufzulisten. Da der Unterordner <strong>html<\/strong> in das Wurzelverzeichnis, welches der Webserver ausliefert, gemountet wird, kann man hier eine Index-Seite anlegen und etwa die PHP-Info ausgeben:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">echo &#039;&lt;?php phpinfo();&#039; &gt; html\/index.php<\/code><\/pre>\n<p>Statt des Fehlers f\u00fchrt Apache das Skript mit dem PHP-Modul aus, sodass <strong>php.demo.u-labs.de<\/strong> nun Informationen \u00fcber die eingesetzte PHP-Umgebung anzeigt:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"428\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31-1024x428.png\" alt=\"\" class=\"wp-image-8878\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31-1024x428.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31-300x125.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31-768x321.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31-70x29.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-31.png 1166w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">Erweiterte Regeln f\u00fcr den Router und Middlewares<\/h2>\n<p>Beide Containern haben nur eine einzige, recht simple Regel auf den Domainname (Hostname). Traefik beherrscht aber auch komplexere Regeln, die aus verschiedenen Bedingungen bestehen k\u00f6nnen. Eine UND-Verkn\u00fcpfung mit &amp;&amp; legt fest, dass beide Bedingungen erf\u00fcllt sein m\u00fcssen. Bei ODER (||) muss mindestens eine erf\u00fcllt sein, aber nicht zwingend eine.<\/p>\n<p>Mit folgendem Label erg\u00e4nzen wir die Regel etwa um ein Prefix f\u00fcr den Pfad. Das hei\u00dft: Der Container ist nicht mehr unter <strong>php.demo.u-labs.de<\/strong> erreichbar (also im Wurzelverzeichnis, Pfad = \/) sondern unter <strong>php.demo.u-labs.de\/test<\/strong> bzw. alle Pfade, die mit <strong>\/test<\/strong> beginnen (auch etwa <strong>\/test123<\/strong>)<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">traefik.http.routers.apache.rule=Host(`php.demo.u-labs.de`) &amp;&amp; PathPrefix(`\/test`)<\/code><\/pre>\n<p>Dadurch liefert <strong>php.demo.u-labs.de<\/strong> nun einen 404 Fehler von Traefik, weil die Route neben dem Host auch fordert, dass der Pfad mit <strong>\/test <\/strong>beginnt. Im Wurzelverzeichnis lautet der Pfad <strong>\/<\/strong> somit ist die zweite Bedingung nicht erf\u00fcllt. Unter <strong>php.demo.u-labs.de\/test<\/strong> erscheint ein Fehlermeldung des Apache:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-32.png\"><img loading=\"lazy\" decoding=\"async\" width=\"755\" height=\"529\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-32.png\" alt=\"\" class=\"wp-image-8879\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-32.png 755w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-32-300x210.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-32-70x49.png 70w\" sizes=\"auto, (max-width: 755px) 100vw, 755px\" \/><\/a><\/figure>\n<\/div>\n<p>Unser Routing im Traefik funktioniert also grunds\u00e4tzlich, da der Fehler nicht mehr von Traeffik kommt, sondern vom Apache dahinter Das zeigt die Besonderheiten von Pfaden: Der Reverse Proxy Traefik reicht diese standardm\u00e4\u00dfig durch, d.H. der Webserver dahinter sucht nun nach einem Ordner namens <strong>test<\/strong>. Pfade sind echten Anwendungen etwas schwierig umzusetzen, da diese den Pfad unterst\u00fctzen m\u00fcssen. Hei\u00dft: Die Anwendung sollte im Optimalfall konfiguriert werden k\u00f6nnen, dass ihre Basis-Adresse etwa <strong>php.demo.u-labs.de<\/strong> lautet.<\/p>\n<p>Alternativ (falls das z.B. nicht m\u00f6glich ist), kann man daf\u00fcr eine Middleware einsetzen. Es gibt verschiedene Middlewares, welche die Anfrage oder auch Antwort auf bestimmte Arten ver\u00e4ndern. Beispielsweise um die Antwort des Containers zu ver\u00e4ndern. Hier ben\u00f6tigen wir die <strong>StripPrefix<\/strong>-Middleware: Sie manipuliert die Anfrage, bevor Traefik sie an den Container leitet. Konkret entfernt sie einen angegebenen Pfad: Bei Traefik kommt <strong>php.demo.u-labs.de\/test<\/strong> an, Traefik entfernt <strong>\/test <\/strong>und aus Sicht des Anwendungsservers (hier Nginx) lautet die Anfrage <strong>php.demo.u-labs.de<\/strong>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">traefik.http.middlewares.strip-testpath.stripprefix.prefixes=\/test\ntraefik.http.routers.apache.middlewares=strip-testpath@docker<\/code><\/pre>\n<p>Diese zwei Label definieren eine Middleware, die das Prefix <strong>\/test<\/strong> im Pfad entfernt und nennt diese <strong>strip-testpath<\/strong>. Auch dies ist frei w\u00e4hlbar, muss aber im n\u00e4chsten Schritt mit dem festgelegten Name angesprochen werden: Dort aktivieren wir die definierte Middleware f\u00fcr den Docker-Provider. Nun wird wieder die index.php mit der PHP-Info im Wurzelverzeichnis angezeigt:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"366\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33-1024x366.png\" alt=\"\" class=\"wp-image-8881\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33-1024x366.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33-300x107.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33-768x274.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33-70x25.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-33.png 1151w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n<p>Bei echten Anwendungen muss man hier aber Bedenken, dass die Applikation hinter Traefik das in der Regel nicht ber\u00fccksichtigt. Wenn diese z.B. Links generiert, lauten diese <strong>php.demo.u-labs.de<\/strong> und nicht <strong>php.demo.u-labs.de\/test<\/strong>. Diese w\u00fcrden ins Leere laufen, da Traefik wiederum ja nicht auf <strong>php.demo.u-labs.de<\/strong> ohne den <strong>\/test<\/strong> Pfad reagiert. Viele Systeme eine Einstellung f\u00fcr die Basis-URL, womit sich das korrigieren l\u00e4sst.<\/p>\n<h2 class=\"wp-block-heading\">Auslagern der Traefik-Konfiguration in eine eigene Datei<\/h2>\n<p>Bisher haben wir s\u00e4mtliche Konfigurationseinstellungen \u00fcber Kommandozeilenargumente im Startbefehl \u00fcbergeben. Das mag anfangs bequem sein, allerdings f\u00fchrt dies schnell zu langen Befehlen und wird un\u00fcbersichtlich.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"277\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34-1024x277.png\" alt=\"\" class=\"wp-image-8882\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34-1024x277.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34-300x81.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34-768x208.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34-70x19.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/04\/grafik-34.png 1499w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n<p>Alternativ kann man eine eigene Yaml-Datei festlegen und die Konfiguration dort hierarchisch vornehmen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">--providers.file.filename=\/traefik.yml<\/code><\/pre>\n<p>Die Datei muss entsprechend noch als Volume gemountet werden:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">volumes:\n  - .\/traefik.yml:\/traefik.yml<\/code><\/pre>\n<p>In Yaml \u00fcbersetzt, sehen die Startparameter wie folgt aus:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">providers:\n  docker:\n    exposedByDefault: false\n    network: traefik_web\n\nentryPoints:\n  http:\n    address: &quot;:80&quot;\n    http:\n      redirections:\n        entryPoint:\n          to: &quot;https&quot;\n          scheme: &quot;https&quot;\n  https:\n    address: &quot;:443&quot;\n    http:\n      tls:\n        certResolver: le\n\ncertificatesResolvers:\n  le:\n    acme:\n      tlschallenge: true\n      email: &quot;deine@mail.de&quot;\n      storage: &quot;\/letsencrypt\/acme.json&quot;<\/code><\/pre>\n<p>Vor allem bei l\u00e4ngeren Pfaden in denen mehrere \u00c4nderungen vorgenommen werden, spart man sich durch die Hierarchische Struktur das Wiederholen. Etwa bei <strong>entrypoints.http.http.redirections.entrypoint<\/strong>. Zudem durch das Einr\u00fccken besser ersichtlich, was wohin geh\u00f6rt. Daher ist das meiner Meinung nach die bessere Alternative. Schlussendlich aber Geschmackssache, beide Wege funktionieren.<\/p>\n<h2 class=\"wp-block-heading\">Detailliertere Logs zur Fehleranalyse<\/h2>\n<p>Falls es zu Problemen kommt, kann es hilfreich sein, das Log-Level zu erh\u00f6hen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">--log.level=DEBUG<\/code><\/pre>\n<p>\u00dcber die Logs des Containers (z.B. <strong>docker logs -f traefik-traefik-1<\/strong>) sieht man dann detailliertere Informationen. <\/p>\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n<p>Traefik ist ein Reverse Proxy, der sich tief in die Docker-Umgebung installiert. Mit wenigen Zeilen Konfigurationsaufwand kann man mehrere Container \u00fcbers Web erreichbar machen. Durch die Let&#8217;s Encrypt Integration auch mit HTTPS und automatischer Verl\u00e4ngerung der Zertifikate. <\/p>\n<h2 class=\"wp-block-heading\">Weiterf\u00fchrende Informationen<\/h2>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/doc.traefik.io\/traefik\/\" title=\"Offizielle Traefik-Dokumentation\" target=\"_blank\" rel=\"nofollow\">Offizielle Traefik-Dokumentation<\/a><\/li>\n<li><a href=\"https:\/\/doc.traefik.io\/traefik\/reference\/static-configuration\/cli\/\" target=\"_blank\" rel=\"nofollow\">Auflistung aller Kommandozeilenparameter<\/a><\/li>\n<li><em><a href=\"https:\/\/www.benjaminrancourt.ca\/a-complete-traefik-configuration\/\" title=\"A Complete Traefik Configuration\" target=\"_blank\" rel=\"nofollow\">A Complete Traefik Configuration<\/a><\/em><\/li>\n<li><a href=\"https:\/\/gist.github.com\/Mau5Machine\/00401feb19433cf0387cc66c8e90c26c\" title=\"Zugriffsregeln f\u00fcr die API des Dashboards festlegen\" target=\"_blank\" rel=\"nofollow\">Zugriffsregeln f\u00fcr die API des Dashboards festlegen<\/a><\/li>\n<li><a href=\"https:\/\/dev.to\/cedrichopf\/get-started-with-traefik-2-using-docker-compose-35f9\" title=\"Beispiel, bei dem mehr Konfiguration in die Dienste selbst verlagert wird statt global zu Traefik \" target=\"_blank\" rel=\"nofollow\">Beispiel, bei dem mehr Konfiguration in die Dienste selbst verlagert wird statt global zu Traefik <\/a>(n\u00fctzlich, wenn man stark abweichende Anforderungen hat)<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Wer mehrere Webanwendungen auf einem Server betreiben m\u00f6chte, ben\u00f6tigt einen Reverse Proxy. Wie das Konzept in der Theorie funktioniert, habe ich in einem eigenen Beitrag ausf\u00fchrlicher erkl\u00e4rt. Hier schauen wir uns die praktische Einrichtung von Traefik an. Ob ihr dabei einen Raspberry Pi mit Raspberry Pi OS verwendet, eine lokale VM oder einen Cloudserver, spielt &#8230;<\/p>\n","protected":false},"author":5,"featured_media":8915,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[883,62],"tags":[1041,847,1011,937],"class_list":["post-8870","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker-containertechnologie","category-server","tag-https","tag-reverse-proxy","tag-ssl","tag-webserver"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=8870"}],"version-history":[{"count":14,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8870\/revisions"}],"predecessor-version":[{"id":14190,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8870\/revisions\/14190"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/8915"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=8870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=8870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=8870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}