Dieser Beitrag wurde seit einem Jahr nicht mehr aktualisiert. Im Internet ist das manchmal eine halbe Ewigkeit. Es kann daher sein, dass die Informationen und Links nicht mehr aktuell sind.
Wie im vorherigen Beitrag bereits angedeutet, war es etwas aufwendiger auf relevante Dienste meines Smarthome-Stacks auch außerhalb des heimischen Netzwerks zugreifen zu können. In erster Linie ging es um den Zugriff auf HomeAssistant. Hier kam der Reverse Proxy Traefik ins Spiel.
Gerade im Smarthome-Bereich ist es wichtig, auch unterwegs auf die Anwendungen im privaten Netzwerk zugreifen zu können. Es gibt mehrere Möglichkeiten, diesen Zugriff zu ermöglichen.
- VPN Zugriff: Über einen eingerichtetes VPN (Virtual-Private-Network) kann man aus einem externen Netz auf das entfernte, private Netzwerk zugreifen. Ist der Zugang eingerichtet und aktiv, ist es so als wäre man vor Ort. Jedoch muss die Verbindung manuell aufgebaut werden.
- Portfreigaben: Über die Einrichtung einer Portfreigabe lassen sich die Dienste extern aufrufen. Grundsätzlich muss für jeden Dienst, der extern erreichbar sein soll, eine Portfreigabe erfolgen.
- Reverse Proxy: Ein Reverse Proxy benötigt, sofern er Zuhause betrieben wird, ebenfalls eine Portfreigabe. Allerdings ist hier nur die Freigabe von wenigen Ports (in der Regel nur die Ports 80 und 443) notwendig. Der Reverse Proxy routet die Anfrage des externen Clients dann über verschiedene Parameter an einen oder mehrere Server und liefert das Ergebnis (hier konkret das Frontend einer Anwendung) an den Client.
Während lange Zeit häufig NGINX als ReverseProxy genutzt wurde, taucht im Zusammenhang mit Docker immer häufiger Traefik als Anwendung auf. Traefik ist gegenüber NGINX gerade im Zusammenhang mit Docker leichter zu konfigurieren. Zum Beispiel lassen sich bei der Containerdefinition in der docker-compose.yaml
einige Labels ergänzen, die verschiedene Parameter an Traefik übermitteln. Anhand der Parameter (z.B. dem Host) entscheidet Traefik an welchen Container die Anfrage geroutet wird. Dazu aber später mehr.
Externe Erreichbarkeit des privaten Netzwerks
Zunächst muss sichergestellt sein, dass unser Netzwerk von außen erreichbar ist. Neben der oben erwähnten Portfreigabe im Router benötigt man, sofern der eigene Anschluss keine feste IP-Adresse hat, einen DynDNS Dienst und eine Domain. Viele Router können dann so konfiguriert werden, dass die jeweils aktuelle IP-Adresse an den DynDNS-Dienst übermittelt wird.
Sowohl DynDNS als auch eine Subdomain gibt es kostenlos bei DuckDNS. Dort kann man sich über verschiedene Dienste einen kostenlosen Account samt einer Subdomain anlegen. Im Anschluss muss dafür gesorgt werden, dass die jeweils aktuelle IP-Adresse an DuckDNS übertragen wird. In der FritzBox findet man die Einstellung im Menü unter Internet - Freigaben unter dem Tab DynDNS. Neben dem obligatorischen Haken im Feld DynDNS benutzen muss ein Benutzerdefinierter Dienst angegeben werden. Für DuckDNS muss die folgende URL eingegeben werden:
https://www.duckdns.org/update?domains=<domain>&token=<pass>&ip=<ipaddr>&ipv6=<ip6addr>
Domain, Benutzername und Kennwort (der Token) lassen sich der DuckDNS Übersicht entnehmen. Die FritzBox ersetzt die Platzhalter in der URL mit den in den Feldern angegeben Werten und fügt sowohl die klassische IP-Adresse und auch die neue IPV6 Adresse hinzu. Bei jeder Änderung der öffentlichen IP-Adresse wird die neue Adresse jetzt automatisch an DuckDNS übertragen.
Wo einmal die Einstellungen des Routers offen sind, können wir auch gleich die benötigten Ports freischalten. Unter dem gleichem Menüpunkt lässt sich der Tab Portfreigaben finden. Dort lassen sich Geräte für Freigaben hinzufügen. Nach der Auswahl des Gerätes im Dropdown-Menü können über Neue Freigabe die Ports freigeben werden. Dazu wählt man die Einstellung wie im Screenshot gezeigt.
Konfiguration von Traefik und HomeAssistant
Nachdem die Verbindung von außen vorbereitet ist, müssen wir unserem Smarthome noch beibringen was es bei einem Aufruf zu tun hat. Dazu fügen wir als erstes unserer docker-compose.yaml
den Traefik Container hinzu.
traefik:
container_name: traefik
image: traefik:v2.2
restart: unless-stopped
ports:
- 80:80
- 443:443
- 8080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./volumes/traefik/traefik.yml:/etc/traefik/traefik.yml
- ./volumes/traefik/acme.json:/acme.json
Und der Eintrag von HomeAssistant wird um folgende Labels ergänzt.
labels:
- "traefik.enable=true"
- "traefik.http.routers.homeassistant.rule=Host(`ha.subdomain.duckdns.org`)"
- "traefik.http.routers.homeassistant.entrypoints=websecure"
- "traefik.http.routers.homeassistant.tls=true"
- "traefik.http.routers.homeassistant.tls.certresolver=letsencrypt"
Zum Stand des Posts verwenden wir die erst kürzlich erschiene Version 2.2. Wie man der Konfiguration entnehmen kann, benötigen wir jetzt noch zwei Dateien, die wir beide unter dem angegebenen Pfad erstellen. Die traefik.yml
dient der Festlegung von Grundeinstellungen. Diese können zwar auch über CLI-Parameter beim Starten des Containers festgelegt werden, ich empfinde eine weitere Datei aber als übersichtlicher.
Die zum HomeAssistant-Eintrag hinzugefügten Labels konfigurieren die Route für HomeAssistant in Traefik. Hier muss der Host individuell auf eure Domain angepasst werden. Zahlreiche Möglichkeiten samt Beispielen findet man in der Traefik-Dokumentation.
Wer in HomeAssistant die Homekit Integration nutzen möchte, muss ebenfalls noch den Port 51827 mit 51827:51872
zum Port-Mapping hinzufügen.
# traefik.yml
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
api:
dashboard: true
insecure: true
providers:
docker:
exposedByDefault: false
network: pi_default
certificatesResolvers:
letsencrypt:
acme:
email: mail@example.com
storage: acme.json
httpChallenge:
entryPoint: web
Für einen Überblick schauen wir uns kurz die gewählten Einstellungen an.
- Die entryPoints sind die Schnittstellen nach außen. Auf diesen Ports lauscht Traefik nach eingehenden Verbindungen. Hier wird auch direkt für eine sichere Verbindung gesorgt. Alle Verbindungen von extern über den Port 80 werden automatisch auf den Port 443 umgeleitet.
- Die api Konfiguration erzeugt ein Dashboard, auf welchem man die aktiven Routen von Traefik bequem einsehen kann. Da das ganze nur lokal genutzt wird, setzen wir
insecure
auftrue
. - Als Provider nutzen wir Docker, das bedeutet, dass Traefik automatisch die vorhanden Docker Container überwacht. Damit nicht alle Container automatisch eine externe Verbindung erhalten, wird exposedByDefault auf
false
gesetzt. Das Netzwerk muss dem Netzwerk der Container entsprechen. - Die certificatesResolvers sorgen mit Let’s Encrypt für ein kostenloses SSL-Zertifkat. Traefik nimmt einem sowohl die Beantragung als auch die regelmäßige Erneuerung des Zertifikates ab. Bei diesem Eintrag muss zwingend die E-Mail Adresse geändert werden.
Die acme.json
enthält später die Zertifikate für die SSL-Verschlüsselung unserer Verbindung. Hier ist wichtig, dass die Berechtigungen richtig gesetzt werden. Die Datei benötigt zwingend die Rechte 600. Diese setzen wir mit
sudo chmod 600 ~/volumes/traefik/acme.json
Jetzt starten wir mit docker-compose up -d --build homeassistant
zuerst HomeAssistant neu. Der Parameter --build
sorgt dafür, dass der Container mit den Labels neu gebaut wird. Der Befehl docker-compose up -d traefik
lädt dann das Traefik Image herunter und startet den Container im Hintergrund.
Traefik Dashboard
Traefik bietet ein Dashboard auf welchem sich die erkannten Routen einsehen lassen. Gerade zu Beginn kann das eine hilfreiche Übersicht sein.
Neben einigen internen Routen für die API und das Dashboard sollte jetzt auch HomeAssistant aufgeführt und von außen über die Host-URL
erreichbar sein.
Homekit trotz Docker Container
Es wäre natürlich zu schön, wenn jetzt bereits alles funktionieren würde. Allerdings macht die Homekit Integration von HomeAssistant trotz Portmapping noch einen Strich durch die Rechnung. Ursache ist, das der Homekit Dienst so noch nicht über den Avahi-Daemon im lokalen Netzwerk bekannt gemacht wird. Nach etwas Recherche bin ich in der HomeAssistant-Community auf die Lösung gestoßen.
Für eine funktionierende Homekit-Integration in HomeAssistant ergänzt man auf dem Raspberry Pi unter /etc/avahi/services
die Datei homeassistant.service
mit folgendem Inhalt:
<!-- homeassistant.service -->
<service-group>
<name>Home Assistant Bridge</name>
<service>
<type>_hap._tcp</type>
<port>51827</port>
<txt-record>md=HA Bridge</txt-record> <!-- friendly name -->
<!-- the following appear to be mandatory -->
<txt-record>pv=1.0</txt-record> <!-- HAP version -->
<txt-record>id=AA:BB:CC:DD:EE:FF</txt-record> <!-- MAC (from `.homekit.state`) -->
<txt-record>c#=2</txt-record> <!-- config version -->
<!-- the following appear to be optional -->
<txt-record>s#=1</txt-record> <!-- accessory state -->
<txt-record>ff=0</txt-record> <!-- unimportant -->
<txt-record>ci=2</txt-record> <!-- accessory category (2=bridge) -->
<txt-record>sf=1</txt-record> <!-- 0=not paired, 1=paired -->
<txt-record>sh=UaTxqQ==</txt-record> <!-- setup hash (used for pairing) -->
</service>
</service-group>
Drei wichtige Punkte müssen richtig sein:
- HAP-Version (aktuell 1.0)
- MAC-Adresse von Homekit. Diese findet ihr in den Konfigurationsdateien von HomeAssistant unter
.storage
. Die Datei heißthomekit.<xyz>.state
wobei xyz eine zufällige Zeichenfolge ist. - Config Version: Ebenfalls in der
.homekit.state
zu finden.
Ist der Service angelegt und gespeichert, muss Avahi mit sudo service avahi-daemon restart
neu gestartet werden. HomeAssistant sollte dann nun auch als Bridge zu Homekit hinzugefügt werden können.
Die oben genannten Befehle sind für die Verwendung auf einem Raspberry Pi ausgelegt. Die Anleitung funktioniert analog aber auf fast jedem Linux, also auch auf einer Synology Diskstation.
Andere Dienste freigeben
Natürlich kann Traefik mehr als nur einen Container nach außen freigeben. Sonst könnte man abgesehen von der SSL-Verschlüsselung ja auf eine normale Portfreigabe zurückgreifen. Um weitere Dienste von außen zu erreichen, ergänzt man an den jeweiligen Container-Definitionen die Labels wie im Beispiel zu HomeAssistant. Für Node-RED würde das ganze dann in etwa so aussehen:
nodered:
container_name: nodered
image: nodered/node-red
restart: unless-stopped
user: "0"
privileged: true
environment:
TZ: Europe/Berlin
ports:
- 1880:1880
volumes:
- ./volumes/nodered/data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.homeassistant.rule=Host(`nodered.subdomain.duckdns.org`)"
- "traefik.http.routers.homeassistant.entrypoints=websecure"
- "traefik.http.routers.homeassistant.tls=true"
- "traefik.http.routers.homeassistant.tls.certresolver=letsencrypt"
Wie auch zuvor muss die Domain angepasst werden.
Achtung! Alle Container, an die Traefik routet, sind über den Hostnamen im Internet offen zugänglich. Daher sollten alle Dienste vernünftig abgesichert sein und mindestens mit einen Passwort geschützt sein.
Bringt die Anwendung keinen Passwortschutz mit sich, kann in Traefik eine zusätzliche Middleware mit einer HTTP-Basic-Authentifizierung aktiviert werden. Weitere Information gibt es in der Traefik Dokumentation.
Optional: Einem Container eine eigene IP zuweisen
Manchmal ist es sinnvoll, dass der Container eine eigene IP-Adresse hat. Damit wird er wie ein physisches Gerät im Netzwerk behandelt und alle Ports sind nutzbar.
Zunächst muss ein neues Docker-Netzwerk erstellt werden.
docker network create -d macvlan -o parent=eth0 --subnet 192.168.178.0/24 --gateway 192.168.178.1 --ip-range 192.168.178.224/27 --aux-address 'host=192.168.178.254' macvlan0
Anschließend kümmern wir uns um den Rest.
sudo ip link add macvlan-shim link eth0 type macvlan mode bridge
sudo ip addr add 192.168.178.254/32 dev macvlan-shim
sudo ip link set macvlan-shim up
sudo ip route add 192.168.178.224/27 dev macvlan-shim
tl;dr
Die Einrichtung von Traefik sieht zwar auf den ersten Blick kompliziert aus, ist sie aber dem Grunde nach nicht. Wer sich an diese kleine Anleitung hält und ein wenig Zeit investiert, erhält ein flexibles System, um interne Anwendungen schnell und sicher außerhalb des eigenen Netzwerks verfügbar zu machen. Zudem ist die Lösung vollkommen kostenfrei und benötigt abgesehen von einem DynDNS Dienst keine externen Lösungen.
In einem der letzten Posts habe ich ein kleines Tool vorgestellt, welches einem die Installation von Docker und die Anlage der Docker-Compose Datei abnimmt. Auf einem Raspberry Pi muss dazu auf der Kommandozeile nur der Befehl curl -ssL https://himpler.com/smarthome-setup | sh
ausgeführt werden. Das Script wurde nun um Traefik und HomeAssistant ergänzt. Die benötigten Dateien aus dieser Anleitung müssen selbst angelegt werden.