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.
Zuletzt benötigte ich über eine HTTP-API Zugriff auf einige Daten aus meinem Heimnetzwerk. Der Zugriff musste auch ohne VPN von unterwegs funktionieren und sollte mit einer Authentifizierung geschützt sein. Wie sich so etwas leicht und schnell mit Node-RED und Traefik als Reverse Proxy umsetzen lässt, zeige ich in diesem Post.
Erzeugung einer API mit Node-RED
Ich nutze Node-RED zur Erstellung der API. Node-RED bringt dazu nicht nur bereits alles mit, sondern macht die Erstellung der Schnittstelle durch die GUI auch ziemlich einfach. Stehen die Daten schon irgendwo zur Verfügung ist das in wenigen Minuten erledigt.
In meinem Fall kommen die Daten eventbasiert aus unterschiedlichen Quellen und werden nach Ankunft mit einer Funktion (siehe unten) im Kontext des Flows gespeichert. Wird die API über eine URL aufgerufen, wird der jeweils aktuelle Stand der Daten aus dem Flow-Kontext geladen und als JSON
ausgegeben.
const context = flow.get('somerandomkey') || {};
context[msg.topic] = msg.payload;
flow.set('somerandomkey', context);
return msg;
Die API öffentlich bereitstellen
Grundsätzlich ist die Node-RED Instanz nur innerhalb meines Netzwerks erreichbar. Und das soll, abgesehen von der HTTP-API, auch so bleiben. Da ich ohnehin schon Traefik als Reverse Proxy nutze, bietet sich dieses geniale Tool auch zur Freigabe der gebauten Schnittstelle an. Praktischerweise bringt Traefik bereits von Haus aus eine BasicAuth-Middleware mit. Diese schützt eine Route dann mit dem Basic-Authentifizierungsverfahren. Details zur Funktion gibt es auch in der Traefik-Dokumentation.
File Service Provider
Damit nicht die gesamte Node-RED Instanz im Netz landet, greife ich anstelle des Docker Service Providers in diesem Fall auf den File Service Provider zurück. Dieser wird zuerst in der Traefik Konfiguration aktiviert:
# traefik.yml
# ...
providers:
file:
filename: "/etc/traefik/dynamic_conf.yml"
watch: true
# ...
Die Anpassung der traefik.yml
ist fast selbsterklärend. Den Providern wird ein neuer Eintrag hinzugefügt. Der filename
verweist dabei auf eine noch zu erstellende Konfigurationsdatei, watch
sorgt für die automatische Überwachung von Änderungen. Sonst wäre bei jeder späteren Änderung ein Neustart von Traefik erforderlich.
Jetzt wird die oben referenzierte Datei befüllt:
# dynamic_conf.yml
http:
routers:
node-red-api-router:
rule: "Host(`api.example.com`)"
service: node-red-api
middlewares:
- "api-auth"
- "add-api-prefix"
entrypoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
add-api-prefix:
addPrefix:
prefix: "/api"
api-auth:
basicAuth:
users:
- "someusername:$fy$95$A19KTpomnUW1NoszBcS"
services:
node-red-api:
loadBalancer:
servers:
- url: "http://192.168.1.99:1880"
Middleware
Beginnen wir mit den Middlewares. Zum einen wird die Middleware basicAuth
konfiguriert. Dort wird ein User unter Angabe eines BasicAuth-Strings angelegt. Zur Vereinfachung gibt es online zahlreiche Tools, die einem den passenden String generieren.
Jetzt müssen wir Traefik noch beibringen, dass unsere API unter dem Pfad /api
erreichbar ist. Über die addPrefix
Middleware wird jedem eingehenden Request ein /api
vorangestellt. Somit ist auch sichergestellt, das selbst eingeloggte User nicht auf einen Pfad oberhalb des Prefix zugreifen können.
Service
Damit Traefik weiß, wohin eingehende Requests gesteuert werden sollen, definieren wir einen Service mit dem Namen node-red-api
. Dieser wird mit der lokalen URL der Node-RED Instanz, also z.B. http://192.168.1.99:1880
konfiguriert. Node-RED kann also auch ohne weiteres auf einem anderen Gerät betrieben werden.
Router
Jetzt legen wir die Route an und binden die Middlewares und den Service daran an. Die rule
wird mit dem gewünschten Hostnamen definiert, also der jeweiligen URL die auf Traefik verweist und unter der die Schnittstelle erreichbar sein soll. Im Post zum Einsatz von Traefik mit Docker habe ich z.B. den kostenfreien Dienst DuckDNS verwendet.
Unter dem Punkt service
listen wir unseren node-red-api
Service auf und unter middlewares
entsprechend die Namen unserer Middlewares. Über den Entrypoint wird festgelegt, dass unsere API nur über HTTPS (Port 443) erreichbar ist. Damit unsere API auch ein gültiges Zertifikat hat, fügen wir über tls
→ certresolver
unseren Zertifikat-Resolver hinzu. Die Konfiguration der letzten beiden Punkte wird auch im oben verlinkten Post erläutert.
Test der API
Da wir eine Änderung an der Hauptkonfiguration von Traefik gemacht haben, starten wir Traefik zunächst neu. Ruft man jetzt https://api.example.com/endpoint
(die URL muss natürlich durch eure eigene ersetzt werden) im Browser auf, sollte das BasicAuth Anmeldefenster erscheinen. Mit den festgelegten Benutzerdaten könnt ihr euch anmelden und seht dann die Ausgabe des Aufrufs. Für einen automatisierten Abruf muss im Request der Authorization-Header gefüllt sein.
Fazit
Mit Hilfe von Node-RED und Traefik lässt sich sehr leicht eine öffentliche API-Schnittstelle mit SSL Verschlüsselung bauen. Über den FileServiceProvider lässt sich der Reverse Proxy übersichtlich in einer Datei konfigurieren. Dank SSL und BasicAuth ist der Service zumindest etwas geschützt. Hochsensible Daten sollte man so aber besser nicht bereitstellen. Wenn Du dich an der Anleitung orientierst gilt wie immer: Ich übernehme keine Haftung falls doch mal was schief geht.