himpler.com himpler.com

Lokale Domains mit Traefik und Pi-hole

In einem der vergangenen Beiträge ging es um die Einrichtung von Traefik als Reverse Proxy für HomeAssistant. Während es dabei vorwiegend um die externe Erreichbarkeit ging, geht es in diesem Post um das Mapping von lokalen Domains auf unterschiedliche Ports eines Servers.

Hintergrund

Mit steigenden Aufgaben unseres Smarthome- bzw. Heimservers wird es immer schwieriger sich die Ports der einzelnen Dienste zu merken. HomeAssistant, Esphome, Node-RED, Portainer, ein Adminstrationstool für Datenbanken, Grafana, Influx-DB (u.s.w. …) sind dank eines Docker-Stacks alle auf dem gleichen Server unter unterschiedlichen Ports erreichbar. Natürlich könnte man die Dienste über Favoriten, Shortcuts oder individuelle Hosteinträge in der /etc/hosts/ ansprechen. Allerdings müsste dies auf jedem Client manuell eingerichtet und gepflegt werden. Ein erheblicher Aufwand, den man zum Glück mit einer Alternative umgehen kann.

Installation von Pi-hole

Da hier Traefik und Pi-hole bereits im Einsatz sind, greifen wir auf eine Kombination der beiden Tools zurück. Wer Pi-hole noch nicht in seinem Stack hat, findet hier eine passende Beispielkonfiguration für die docker-compose.yml.

pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "8089:80/tcp"
    env_file:
      - ./.env/pihole.env
    volumes:
       - ./volumes/pihole/etc-pihole/:/etc/pihole/
       - ./volumes/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/
    dns:
      - 127.0.0.1
      - 1.1.1.1
    cap_add:
      - NET_ADMIN
    restart: unless-stopped

Dazu werden über die oben genannte ENV-Datei folgende Umgebungsvariablen gesetzt:

TZ=Europe/Berlin
WEBPASSWORD=supersecret
ServerIP=192.168.1.34
INTERFACE=eth0
DNS1=9.9.9.9
DNS2=149.112.112.112

Die Werte müssen dann eurer Konfiguration entsprechend angepasst werden. Das Webpassword dient dem späteren Aufruf des Webinterfaces, die Server-IP ist die IP-Adresse des Docker-Hosts und das Interface ist die Netzwerkschnittstelle über die der Host ans lokale Netz angebunden ist. Mit docker-compose up -d pihole wird das Image geladen und der Container gestartet.

Konfiguration von Traefik

Bevor es mit Pi-hole weitergeht, kümmern wir uns um die Konfiguration von Traefik. Ich zeige hier nur die Ausschnitte, die für den lokalen Zugriff benötigt werden. Falls ihr schon dem alten Post gefolgt seit, könnt ihr die benötigten Dinge ergänzen.

# traefik.yml

entryPoints:
  web:
    address: ":80"

api:
  dashboard: true
  insecure: true

providers:
  docker:
    exposedByDefault: false
    network: pi_default
    defaultRule: 'Host(`{{ normalize .Name | replace "-pi" "" }}.zuhause`)'

In der Datei wird zunächst ein Zugangspunkt mit der Bezeichnung web und dem Port 80 definiert. Als nächstes aktivieren wir das Dashboard und definieren den Provider. Da wir unsere Aufrufe auf Docker-Container routen wollen, verwenden wir den Docker ServiceProvider. exposedByDefault sorgt dafür, dass unsere Container nicht automatisch über den ReverseProxy zu erreichen sind und das network ist das Netzwerk unseres Docker-Compose Stacks.

Zum Abschluss der Traefik Konfiguration passen wir noch die defaultRule an. Diese gibt vor, nach welcher Regel die Container standardmäßig im Netz erreichbar sein sollen. Hier sind die unterschiedlichsten Regeln und Regelkombinationen möglich. Wir überschreiben den Traefik-Standard und machen unsere Container über den in der docker-compose.yaml definierten Namen erreichbar. Das Suffix -pi welches normalerweise hinzugefügt wird, entfernen wir mit dem replace-Ausdruck. Im obigen Beispiel sieht die URL dann wie folgt aus http://homeassistant.zuhause.

Kleiner Tipp: Die generierten URLs der Dienste werden später auch im Traefik Dashboard angezeigt. So lässt sich die vorgenommene Anpassung der Standardregel einfach überprüfen. Alternativ lässt sich die Standardregel auch wieder je Dienst überschreiben. Hinweise dazu gibts im oben bereits verlinkten Post.

Damit unsere Container nun über Traefik erreichbar sind, müssen wir zum einen Traefik neu starten und zum anderen in unserer docker-compose.yml unseren Containern noch einige Labels verpassen.

Am Beispiel von HomeAssistant sieht das ganze dann wie folgt aus:

homeassistant:
  container_name: homeassistant
  image: homeassistant/home-assistant:stable
  volumes:
    - ./volumes/homeassistant:/config
  environment:
    TZ: Europe/Berlin
  restart: unless-stopped
  network_mode: host
  labels:
    - "traefik.enable=true"
    - "traefik.http.services.homeassistant.loadbalancer.server.port=8123"

Das Label traefik.enable=true sorgt dafür, dass Traefik unseren Container berücksichtig. Dem Grunde nach, reicht dies meistens schon aus. Bei mehreren Ports oder dem network_mode: host müssen wir noch den Port für den Loadbalancer definieren. Nur so weiß Traefik, an welchen Port der Traffic geroutet werden soll.

Nach Neuerstellung des Containers mit docker-compose up -d homeassistant werden die Labels berücksichtigt. Nach wenigen Sekunden sollte dann im Traefik Dashboard (http://<ip-des-docker-hosts>:8080) ein Eintrag für euren Dienst auftauchen.

Anpassung des DNS Servers

Ruft man nun die URL im lokalen Netzwerk auf, funktioniert das nun noch nicht wie gewünscht. Der angesprochene DNS Server kann die URL http://homeassistant.zuhause nicht auflösen, also nicht in eine IP-Adresse übersetzen. Im Prinzip könnte man nun hingehen und auf jedem Rechner die Hosttabelle bearbeiten und die gewünschten URLs auf unseren Docker-Stack verweisen lassen. Wie Eingangs schon erwähnt ein Haufen Arbeit. Eleganter und deutlich einfacher lässt sich das Ganze über Pi-hole managen. Neben der bekannten Funktion eines Werbeblocker bietet Pi-hole auch die Möglichkeit lokale DNS-Einträge zu ergänzen. Damit das funktioniert muss Pi-hole als netzwerkweiter DNS-Server agieren. Dazu wird die IP-Adresse von Pi-hole in den Router Einstellungen als DNS-Server eingesetzt. Fragt nun ein Client den Hostnamen homeassistant.zuhause an, sorgt Pi-hole dafür, dass der Name in die IP-Adresse unseres Docker Hosts übersetzt wird.

Eintrag von Local DNS im Webinterface von PiHole

Im Backend von Pi-hole lassen sich unter dem Menüpunkt Local DNS benutzerdefinierte DNS Einträge hinzufügen. Die Einträge sind denkbar einfach: Neben unserem Hostnamen homeassistant.zuhause wird lediglich noch die Ziel-IP-Adresse benötigt. So können beliebig viele Domains auf eine IP-Adresse verweisen.

Lokale DNS Einträge in Pi-hole

Lokale DNS Einträge in Pi-hole

Wildcard Einträge über /etc/dnsmasq.d

Die Lösung ist schon deutlich besser. Allerdings muss so immer noch für jeden Dienst ein Eintrag hinzugefügt werden. Besser würde das über einen Wildcard-Eintrag funktionieren. Heißt also, dass jede Adresse mit der Endung .zuhause auf unseren Docker-Host verweist.

Zum jetzigen Zeitpunkt unterstützt das Webinterface von Pi-hole noch keine Wildcard-Einträge. Wir können uns aber mit mit einer zusätzlichen Datei behelfen. Diese binden wir dann in unseren Container ein. Wer die oben gezeigte Konfiguration von Pi-hole nutzt, kann die Datei im Verzeichnis ./volumes/pihole/etc-dnsmasq.d/ erstellen. Dort sollte sich bereits eine Datei 01-pihole.conf befinden. Wir erstellen zusätzlich die Datei 03-custom-dns.conf und fügen folgende Zeile ein:

address=/.zuhause/192.168.1.34

Der Dateiname muss mit einer höheren Zahl als 01 beginnen und kann dann einen beliebigen Namen tragen. Der DNS-Dienst liest die Datei nach einem Neustart (Pi-hole - Settings - Restart DNS resolver) automatisch ein. Von nun an werden alle Aufrufe mit der Domainendung .zuhause an unseren Docker-Host weitergeleitet.

Trouble-Shooting

Falls es nicht auf anhieb klappen sollte, fangt mit einem Neustart der Dienste und des Clients an. Sollte das noch nicht zum Erfolg führen, hier noch ein paar Tipps für die Fehlersuche.

Überprüfung mit curl

Das Routing von Traefik kann z.B. mit curl auf Funktion überprüft werden. Mit dem Hostnamen als Header-Parameter und dem Docker-Host als Ziel sollte der Request gelingen.

curl -sIXGET -H Host:homeassistant.zuhause http://192.168.1.34

Eine Antwort sollte z.B. so aussehen:

HTTP/1.1 200 OK
Content-Length: 3327
Content-Type: text/html; charset=utf-8
Date: Wed, 24 Feb 2021 19:18:40 GMT
Server: Python/3.8 aiohttp/3.7.3

Überprüfung der DNS Konfiguration am Client und im Router

War der Test erfolgreich, sollte als nächstes ein Fehler in der DNS Konfiguration des Routers ausgeschlossen werden. Hierzu kann z.B. Pi-hole manuell als DNS Server in den Netzwerkeinstellungen eures Clients (PC, Laptop) eingetragen werden. Funktioniert der Aufruf der homeassistant.zuhause URL, müssen die Einstellungen im Router überprüft werden.

Eine gute Anleitung zur richtigen Konfiguration einer Fritz!Box lässt sich in der Dokumentation von Pi-hole finden.

tl;dr

Mit der Anleitung lassen sich Docker Container im lokalen Netzwerk anstelle von IPs und Ports über leicht zu merkende URLs ansprechen. Mit einer angepassten Standardregel in Traefik sind die Container über ihren Namen und eine beliebige Endung (z.B. http://homeassistant.zuhause) erreichbar. Um nicht die Hostdatei auf allen Clients bearbeiten und pflegen zu müssen, werden benutzerdefinierte DNS-Regeln in Pi-hole, welches als netzwerkweiter DNS-Server fungiert, hinterlegt. Mit einem manuellen Eingriff in die DNS Konfiguration können auch Wildcard Einträge erzeugt werden, so dass die Container automatisch über ein bestimmtes Namensschema erreichbar sind.

Das könnte dir auch gefallen