Die hier im Forum beschriebenen Anleitungen funktionieren sehr gut, wenn man einen eigenen Server im Internet hat oder sein internes System aus dem Internet zugänglich macht. In meiner Anleitung beschreibe ich, wie man in seinem Netzwerk (hinter einer Fritzbox) auf seinem eigenen System die Anleitungen umsetzen kann. Man muss dazu weder sein System aus dem Internet erreichbar machen noch benötigt man einen externen DNS-Server.
Datum | Änderungen |
---|---|
15.03.2024 | Erstellen der Anleitung |
10.06.2024 | Anpassung an aktuelle Anforderungen (docker, etc) |
1. Grundvoraussetzung
2. MultiDNS-Server Avahi installieren
Leider schränkt die Fritzbox im internen Netzwerk etwas ein. Zum einen durch den Gebrauch der festgelegten Domain “fritz.box” und zum anderen, dass es keinen echten DNS-Server auf der Box gibt. Diesen benötigt man aber, um mit Traefik richtig arbeiten zu können. Alle Docker-Container hinter Traefik benötigen einen DNS-Eintrag (einen sogenannten CNAME-Eintrag), der immer auf die IP-Adresse des Traefik-Containers zeigt.
Es gibt (wie immer) viele Möglichkeiten, eine Lösung aufzubauen. Da ich im internen Netz mit meinem Server meine Container entwickle und dann Extern hoste, läuft der interne Server nicht immer. Deshalb muss ich weiterhin den DNS-Server der Fritzbox nutzen. Würde der Server immer laufen, dann könnte ich natürlich dort einen DNS-Server installieren und diesen nutzen. Will ich aber aus Stromspar-Gründen nicht :-).
Aus diesem Grund habe ich mich für einen sogenannten mDNS-Service entschieden. Der MulticastDNS ermöglicht eine automatisierte Auflösung von Rechnernamen in kleinen Netzwerken. Der Service registriert automatisch die Rechnernamen im Netzwerk und stellt sie über DNS-Anfragen zur Verfügung. Die genaue Arbeitsweise findet ihr hier.
Die Installation unter Debian ist recht einfach. Mit
apt install avahi-daemon avahi-utils
wird der Dienst installiert.
Konfigurationsdatei anpassen
Die Konfigurationsdatei wird wie folgt angepasst:
nano /etc/avahi/avahi-daemon.conf
[server] ... browse-domains=<gewünschte Domain, z.B. local> ...
Wichtig ist, dass nicht die identische Domain genutzt wird, die vom eigentlichen DNS-Server schon vergeben wurde. In meinem Falle würde “fritz.box” nicht funktionieren. Da ich faul im tippen bin, habe ich mich kurz und knapp für “local” entschieden.
Jetzt kann der Dienst neu gestartet werden mit
systemctl restart avahi-daemon.service
3. Avahi-Trafik-Helper als Container installieren
Bei Traefik wird jeder Container mit folgendem Eintrag eingebunden
traefik.http.routers.<Name>.rule: (Host (`<DNS-Name>`))
Dieser Name wird über den Avahi-Trafik-Helper direkt an Avahi weitergegeben und ist somit im mDNS registriert und kann genutzt werden.
Wir wechseln in das Verzeichnis, in dem wir die Container-Konfigurationen liegen haben.
cd /opt/containers/
Danach kopieren wir das Git-Repository in dieses Verzeichnis. Es wird automatisch ein neues Verzeichnis mit dem Namen traefik-avahi-helper erzeugt.
git clone https://github.com/hardillb/traefik-avahi-helper.git
Wir erzeugen uns eine Docker-Compose-Datei, mit der wir den Container starten können:
nano /opt/containers/traefik-avahi-helper/docker-compose.yml
services: avahi-helper: build: . container_name: avahi_helper restart: unless-stopped hostname: avahi-helper volumes: - /var/run/docker.sock:/var/run/docker.sock - /run/dbus/system_bus_socket:/run/dbus/system_bus_socket
Interessant an diesem Container ist, dass er keinerlei Netzwerkverbindungen nach extern benötigt. Beim Start des Containers wird ein eigenes Netzwerk angelegt, das aber nicht mit Traefik verbunden ist. Die komplette Kommunikation läuft über die Linux-Sockets.
Nun kann der Container gestartet werden mit
cd /opt/containers/traefik-avahi-helper docker compose up -d
Wird jetzt über den oben genannten Namens-Eintrag ein neuer Container an Traefik gebunden, so ist dieser auch über den Namen im Netzwerk erreichbar.
Ab jetzt sind die System über den Namen erreichbar. Leider nicht mit
nslookup <Name>
Der eigentliche DNS-Server kann die Anfragen nicht beantworten. ein
ping <Name>
funktioniert aber.
4. Eigenes Zertifikat erzeugen
Im internen Netzwerk können wir die Zertifikate von Let’s Encrypt nicht verwenden und müssen uns deshalb eigene Zertifikate erzeugen. Dazu installieren wir das Debian-Paket openssl.
apt install openssl
Danach passen wir einmalig die Datei zur Erzeugung des Zertifikats an.
nano /etc/ssl/openssl.cnf
... [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = <gewünschtes Land, z.B. DE> countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = <gewünschtes Bundesland, z.B. Bayern> localityName = Locality Name (eg, city) localityName_default = <gewünschte Stadt, z.B. Muenchen. Wichtig: Keine Umlaute oder Sonderzeichen!> 0.organizationName = Organization Name (eg, company) 0.organizationName_default = <gewünschte Organisation, z.B. Privat> # we can do this but it is not needed normally 🙂 #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = <gewünschte Unit innerhalb in der Organisation, z.B. Bastelstube> commonName = Common Name (e.g. server FQDN or YOUR name) commonName_max = 64 commonName_default = <Name des Servers, auf dem Docker laeuft, z.B. docker.local. Hier bitte die Domain anpassen, die bei avahi gewaehlt wurde!> emailAddress = Email Address emailAddress_max = 64 emailAddress_default = <eine belibige Mailadresse, z.B. test@test.de> [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] DNS.1=*.<Domain, die bei avahi ausgewaehlt wurde, z.B. local>
Durch den letzten Eintrag DNS.1=*.local erzeugen wir ein sogenanntes Wildcard-Zertifikat, das auf alle Systeme zutrifft, die mit *.local enden. Sonst müssten wir in dieser Datei alle Namen der Containern auflisten, die wir an Traefik anbinden wollen.
Ein beherztes
openssl req -x509 -nodes -days 3650 -keyout docker.key -out docker.crt -extensions 'v3_req'
erzeugt uns das benötigte Zertifikat. Alle Fragen bei der Erstellung einfach mit “Return” beantworten. Die Zertifikaten müssen nach der Installation von Traefik noch an den richtigen Platz kopiert werden
5. Traefik installieren/anpassen
Ab jetzt können wir nach folgender Anleitung arbeiten, müssen jedoch einige Anpassungen durchführen:
Traefik v2 + 3 – Reverse-Proxy mit CrowdSec im Stack einrichten
Die erste Anpassung betrifft die .env-Datei. Hier ist folgender Eintrag zu ändern:
nano /opt/containers/traefik-crowdsec-stack/.env
SERVICES_TRAEFIK_LABELS_TRAEFIK_HOST=`traefik.<mDNS-Domain, z.B. local>`
Die zweite Anpassung muss in der Datei docker_compose.yml durchgeführt werden.
... traefik: ... 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/certs:/etc/certs
Die eigenen Zertifikate werden in der Datei traefik/dynamik_conf.yml eingebunden. In der Datei traefik/traefik.yml müssen die Zertifikats-Resolver auskommentiert werden. Aber alles der Reihe nach:
nano /opt/containers/traefik-crowdsec-stack/traefik/traefik.yml
#certificatesResolvers: # http_resolver: # acme: # email: "deine@email.de" # storage: "acme_letsencrypt.json" # httpChallenge: # entryPoint: web # tls_resolver: # acme: # email: "deine@email.de" # storage: "tls_letsencrypt.json" # tlsChallenge: {}
Komplette Datei
api: dashboard: true metrics: prometheus: addRoutersLabels: true #certificatesResolvers: # http_resolver: # acme: # email: "deine@email.de" # storage: "acme_letsencrypt.json" # httpChallenge: # entryPoint: web # tls_resolver: # acme: # email: "deine@email.de" # storage: "tls_letsencrypt.json" # tlsChallenge: {} 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 Auskommentiert, da in diesem Bereich mein Heimnetz ist forwardedHeaders: trustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 #- 192.168.0.0/16 Auskommentiert, da in diesem Bereich mein Heimnetz ist 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: 10s log: level: "INFO" filePath: "/var/log/traefik/traefik.log" accessLog: filePath: "/var/log/traefik/access.log" bufferingSize: 100
Vielleicht benötigt man die Einträge irgend wann wieder, weshalb ich sie mit Kommentarzeichen versehen würde. Sie können für dieses Setup aber auch gelöscht werden.
nano /opt/containers/traefik-crowdsec-stack/traefik/dynamik_conf.yml
tls: certificates: - certFile: /etc/certs/docker.crt keyFile: /etc/certs/docker.key 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 traefikAuth: basicAuth: users: - "<User>:<HASH Passwort>"
Hier ist wichtig, dass vor “keyFile” kein “-” gesetzt wird. Manche Editoren setzen automatisch das “-“, was aber in diesem Falle zu Fehlern führt.
Jetzt müssen die Zertifikate an den richtigen Platz kopiert werden.
mkdir /opt/containers/traefik-crowdsec-stack/traefik/certs mv docker.key docker.crt /opt/containers/traefik-crowdsec-stack/traefik/certs/
Traefik kann ab jetzt gestartet werden und ist unter dem vergebenen Namen erreichbar. In meinem Beispiel unter traefik.local.
Wird die Seite aufgerufen, so erscheint die Warnung, dass das Zertifikat nicht vertrauenswürde ist. Diese Warnung kann ignoriert werden, da wir das Zertifikat ja selbst erstellt haben (außer wir trauen uns selbst nicht mehr …).
Wen dieses Problem nervt, der kann den erzeugten Schlüssel in seinen Zertifikats-Speicher seines PCs übernehmen.
6. Anpassungen bei Containern hinter Traefik
In den Anleitungen zu Traefik wird immer ein Zertifikat von Let’s Encrypt angefordert. Da wir mit einem eigenen Zertifikat arbeiten, muss ein Eintrag in den docker-compose-Dateien geändert werden.
labels: traefik.enable: true traefik.http.routers.<label>.entrypoints: websecure traefik.http.routers.<label>.rule: Host(`<DNS des Servers, z.B. test.local`) traefik.http.routers.<label>.tls: true traefik.http.routers.<label>.service: <label> traefik.http.services.<label>.loadbalancer.server.port: <Port, auf dem der Docker-Container seine interne Verbindung bereitstellt, meist 80> traefik.http.routers.<label>.middlewares: default@file traefik.docker.network: <Netzwerk, meist "proxy">
Sendet mir gerne eure Anregungen und Tipps. Wie immer: “für mich funktioniert es”, aber es geht bestimmt noch besser 🙂
Hallo bei läuft es leider nicht.
Ping traefik.local geht.
Die Änderung habe ich so übernommen wie in der Anleitung steht.
Ich vermute, dass das selbsterstellte Zertifikat nicht geladen wird.
Beim Aufruf von traefik.local bekomme ich: Die SSL-Gegenstelle hat kein Zertifikat für den angeforderten DNS-Namen.
Im Zertifikat steht unter Subject Alternative Names DNS: *.local Das sollte passen. Wie Docker die Zertifikate lädt habe ich noch nicht verstanden, da wir in der /opt/containers/traefik-crowdsec-stack/traefik/dynamik_conf.yml
angeben. Ich hätte gedacht das müsste /opt/containers/traefik-crowdsec-stack/traefik/certs/ lauten. Falls jemand helfen kann wäre super. Freue mich auch über “Debug-Methoden” also eventuelle Log Einträge, die weiterhelfen könntne.
Hallo ich stehe irgendwie etwas auf dem schlauch und könnte etwas Hilfe gebrauchen.
Und zwar habe ich die Anleitung bis zum Punkt:
erledigt und auch den Code:
eingetragen. Jetzt ist meine Frage ob dann so Schluss ist was da rein kommt oder ob der Rest aus der anderen Anleitung auch noch mit rein kommt? In der anderen Anleitung Traefik v2 + 3 heißt die Datei dynamic_conf.yml.
Ich habe die Anleitung so weiter geführt ( auch Zertifikate verschoben ) wie du es beschrieben hast und dann gestartet. Ich benutze noch einen PiHole im Netzwerk und habe die Adressen dort freigegeben. Ich bekomme beim Aufrufen der Seite traefik.local auch die Meldung so wie es bei dir zu sehen ist. Und wenn ich dann weiter gehe und auf den Link klicke erhalte ich folgende Meldung: 404 page not found
Könnte mir jemand sagen, was ich falsch gemacht habe?
Danke
Vielen Dank für die Anleitung 🙂
Direkt konnte ich “traefik.local” im Netzwerk nicht erreichen.
Ich musste zusätzlich die “hosts”-Datei anpassen.
Gibt es auch eine Möglichkeit, ohne den Eintrag zu setzen?
Viele Grüße 😊
Sehr coole Anleitung!
Sag mal – warum machst Du nicht folgendes:
Coole Anleitung! Vielen Dank dafür.
Allerdings würde mich hier das Self-Signed-Zertifikat stören. Meine Lösung hierfür sieht wie folgt aus:
Ich habe mir ein einem Domainhoster günstig eine Domain geholt und einen A-Eintrag auf eine 192.168.x.x Adresse gelegt. Dann habe ich noch mehrere CNAME-Einträge *.<meine-domain> dort hinterlegt.
Damit löst diese Domain immer fest auf diese IP-Adresse auf.
Im nächsten Schritt habe ich mir den NginxProxyManager installiert. Dort habe ich Lets-Encrypt als SSL-Anbieter konfiguriert und anschließend meine lokalen IP-Adressen einer Subdomain der obigen Domain zugewiesen.
Ich muss hier zwar anders als bei Traefik die Konfiguration im NPM einmalig selbst vornehmen, aber dafür funktioniert diese Lösung a) mit Lets-Encrypt-Zertifikaten und b) auch mit Diensten, die nicht im Container laufen.
Allerdings habe ich dafür jährlich eine Gebühr für die Domain…
Hallo,
prima Anleitung. Funktioniert problemlos, ich habe die Zertifikate (wie auch von MuellEimer vorgeschlagen) mit einem schon länger genutzten XCA erstellt.
Es gibt übrigens auch noch eine Möglichkeit auch im internen Netz (nicht erreichbar aus dem Internet) Let’s Encrypt Zertifikate zu nutzen (via DNS-01 Challenge). Ausführlich hier beschrieben: https://notthebe.ee/blog/easy-ssl-in-homelab-dns01/ . Dadurch werden die Zertifikate problemlos von allen Browsern akzeptiert.
Besten Dank und viele Grüße
Tom
Moin, du schreibst:
Die Zertifikaten müssen nach der Installation von Traefik noch an den richtigen Platz kopiert werden.
Wo ist der richtige Platz?
Kann ich anstatt xxx.local auch xxx.home.arpa verwenden?
Schon mal vielen Dank. Gruß
(: Super Anleitung.
als kleine Anmerkung wer die Zertifikate nicht über die CommandLine erstellen will kann auch das XCA Tool nutzen 🙂 darüber kann auch eine komplette CA auf gebaut werden .
und ggf. die rot makierten erwähnen das diese entfernt werden müssen 🙂