Ein zweiter Docker-Host sollte sauber in Dockhand eingebunden werden – über den Hawser-Agent im Edge-Modus. Was nach einer einfachen Übung aussah, entpuppte sich als anspruchsvoller als gedacht: falsches Container-Image, verwechselter Connection-Type, doppeltes VLAN-Tagging. Ein technischer Rückblick auf Standard- vs. Edge-Modus, die Stolpersteine unterwegs, und das fertige, sauber isolierte Setup.
Ich betreibe zwei Docker-Hosts, verwaltet über Dockhand. Sauber eingebunden war bisher nur der erste – der zweite lief über einen Weg, der mir im Nachhinein nicht mehr gefallen hat. Zeit, das technisch richtig aufzusetzen: über den Hawser-Agent, und zwar im Edge-Modus. Ich habe es nicht beim ersten Anlauf geschafft, und es war herausfordernder, als ich anfangs gedacht hatte – dieser Post zeigt, warum, und wie das Setup am Ende aussieht.
Was Hawser eigentlich ist
Wer wie ich mehrere Docker-Hosts betreibt, kennt das Problem: Man will nicht auf jedem Host einzeln einloggen und Container-Status prüfen, sondern eine zentrale Übersicht. Dockhand ist bei mir genau diese Übersicht. Aber Dockhand muss dafür natürlich irgendwie mit dem Docker-Daemon auf jedem verwalteten Host sprechen können.
Hawser ist der Agent, der das übernimmt. Ein schlanker Container, der auf dem jeweiligen Docker-Host läuft, Zugriff auf den lokalen Docker-Socket hat und die Verbindung zu Dockhand herstellt. Klingt simpel, und im Kern ist es das auch. Der Teufel steckt wie so oft im Detail, nämlich in der Frage: Wer verbindet sich eigentlich zu wem?

Standard oder Edge, das ist hier die Frage
Hawser bietet zwei Betriebsmodi an, und der Unterschied ist grösser, als der Name vermuten lässt.
Im Standard-Modus lauscht der Agent auf dem Docker-Host auf einem Port, und Dockhand baut aktiv eine Verbindung dorthin auf. Klingt erstmal nach dem naheliegenden Weg. Das Problem: Damit das funktioniert, braucht es eine eingehende Firewall-Regel von Dockhands Netzsegment zum Docker-Host. Bei mir, mit sauber getrennten VLANs pro Dienst, ist genau das der Stolperstein, den ich eigentlich vermeiden will. Jede zusätzliche Inbound-Regel zwischen Segmenten ist eine Tür, die ich später wieder im Kopf haben muss.
Im Edge-Modus dreht sich die Richtung um. Der Agent auf dem Docker-Host baut selbst eine ausgehende Verbindung zu Dockhand auf, über WebSocket. Kein offener Port auf dem Zielhost, keine neue Inbound-Regel nötig. Das passt deutlich besser zu meinem Grundsatz, möglichst wenig Ost-West-Traffic zwischen den Segmenten zuzulassen.
Die Entscheidung war für mich damit eigentlich schon gefallen, bevor ich richtig angefangen hatte: Edge, ganz klar.
Der erste Anlauf, der nicht reichte
Ich hatte Hawser für meinen zweiten Docker-Host schon einmal angefangen einzurichten, es aber nicht bis zum fertigen Setup gebracht. Zu Ende gebracht habe ich es erst im Zug eines anderen Problems: mein Graylog-Stack fiel aus, mit einem 502 Bad Gateway.
Die Fehlersuche führte über MongoDB, die in einer Restart-Schleife hing, zu einer fehlenden AVX-Unterstützung auf der CPU des Proxmox-Hosts, auf dem der Container lief. MongoDB ab Version 5 braucht das zwingend, und mein älterer Proxmox-Knoten konnte es schlicht nicht liefern. Die einzige vernünftige Lösung war eine Migration des betroffenen Docker-Hosts auf einen anderen Proxmox-Knoten mit passender CPU.
Damit stand wieder dieselbe Aufgabe an: der Docker-Host musste sauber in Dockhand eingebunden werden. Diesmal habe ich das Setup konsequent zu Ende gebracht – und dabei gemerkt, dass es mehr Stolpersteine hatte, als ich anfangs erwartet hätte.
Wo es harzte
Ganz ohne Umwege ging es dann natürlich doch nicht.
Erste Hürde: das Container-Image. Ich hatte mir irgendwo den Namen falsch notiert und wollte ein Image ziehen, das schlicht nicht existiert. Ein Blick in die offizielle Dockhand-Dokumentation hat das schnell korrigiert, aber es zeigt, wie leicht sich ein Tippfehler in die eigenen Notizen einschleicht und dann hartnäckig hält.
Zweite Hürde: der Connection-Type in Dockhand selbst. Zwischenzeitlich hatte ich aus Versehen „Unix Socket“ statt „Hawser Agent Edge“ ausgewählt. Die Folge war kurios: Dockhand zeigte für beide Docker-Hosts plötzlich identische Werte an, weil es sich in diesem Modus lokal auf denselben Socket bindet, egal welcher Host eigentlich gemeint war. Ein gutes Beispiel dafür, dass eine Fehlkonfiguration nicht immer mit einer Fehlermeldung kommt, manchmal einfach nur mit Daten, die auf den zweiten Blick keinen Sinn ergeben.
Dritte Hürde, und die klassischste von allen bei mir: Netzwerk-Tagging. Ich habe dem Agent-Container ein eigenes, dediziertes VLAN spendiert, wie ich das für alles mache, das Zugriff auf einen Docker-Socket bekommt, denn das ist im Grunde root-Äquivalent und ich will den möglichen Schaden im Zweifel klein halten. Beim Einrichten des Netzwerks im Gastsystem habe ich dann aber versehentlich sowohl auf Proxmox-Ebene als auch im Guest selbst ein VLAN-Tag gesetzt. Doppeltes Tagging, das Ergebnis: „no route to host“. Das ist mittlerweile ein Fehler, den ich im Schlaf erkenne, weil er mir schon öfter begegnet ist. Proxmox taggt bereits auf Bridge-Ebene, im Guest braucht es dafür kein zusätzliches VLAN-Konstrukt, nur ein einfaches Interface.
Zur Kontrolle, ob ein neues Interface im Guest überhaupt angekommen ist, reicht ein einfacher Befehl: ip -br link show. Die Netplan-Konfiguration für das neue Interface bestand am Ende nur aus einem ethernets-Eintrag mit dhcp4 und dhcp6 auf false, ohne jeden zusätzlichen vlans-Block. Genau dieser fehlende Block war der Unterschied zwischen „no route to host“ und einer funktionierenden Verbindung.
Was am Ende steht
Nach diesen drei kleinen Umwegen lief es dann so, wie ich es mir vorgestellt hatte. Der Hawser-Agent im Edge-Modus, isoliert in seinem eigenen VLAN, mit einer Firewall-Konfiguration, die wirklich nur das Nötigste erlaubt: eine ausgehende Verbindung zu Dockhand, und DNS-Auflösung über die Firewall selbst. Kein Ping, keine Regeln aus irgendwelchen generischen Vorlagen, die ich sonst gerne mal übernehme und dann vergesse, wieder aufzuräumen.
Was mir dabei besonders gefällt: Der Agent selbst hat keinerlei Ahnung, in welchem Netz er eigentlich sitzt oder was um ihn herum passiert. Er weiss nur, wohin er sich verbinden soll, und macht das. Alles andere regelt die Firewall. Genau die Art von Trennung zwischen „was macht der Dienst“ und „was darf der Dienst“ mag ich in meinem Homelab am liebsten.
Lessons Learned
Der Edge-Modus ist für ein VLAN-segmentiertes Setup fast immer die bessere Wahl gegenüber dem Standard-Modus. Man spart sich nicht nur eine Firewall-Regel, sondern eine ganze Kategorie von Firewall-Regeln, die man sonst über Zeit ansammelt und irgendwann nicht mehr durchschaut.
Ich habe wieder gelernt, dass ich bei Compose-Dateien und Image-Namen konsequenter mit Copy-Paste statt mit Aus-dem-Kopf-Tippen arbeiten sollte. Klingt banal, kostet mich aber regelmässig Zeit.
Und: Wenn eine Anwendung anfängt, unerklärlich identische Daten für unterschiedliche Quellen anzuzeigen, lohnt sich fast immer ein Blick auf die Verbindungskonfiguration, bevor man tiefer in die Anwendung selbst eintaucht.
Fazit
Auf den ersten Blick sah die Aufgabe simpel aus: einen Agent starten, Verbindung herstellen, fertig. Tatsächlich waren es drei unabhängige Fehlerquellen – Image-Name, Connection-Type, Netzwerk-Tagging –, die sich erst nacheinander zeigten. Jetzt läuft der zweite Docker-Host sauber isoliert im Edge-Modus, ohne offene Inbound-Regeln zwischen meinen Netzsegmenten. Der Aufwand war grösser als gedacht, aber das Ergebnis passt jetzt zu meinem übrigen Setup.
Für alle, die selbst Hawser einrichten wollen
Falls du das Ganze nachbauen willst, hier die wichtigsten Eckpunkte kurz und knapp, ohne die Umwege, die ich selbst gebraucht habe. Zur Einordnung siehe auch die Grafik oben: Standard-Modus verbindet sich von Dockhand zum Agent, Edge-Modus in die andere Richtung.
Das richtige Image heisst ghcr.io/finsys/hawser, mit dem Tag latest. Es gibt eine ähnlich klingende, falsche Variante ohne das „gh“ im Namen, die schlicht nicht existiert. Achte darauf, dass du es wirklich exakt so übernimmst.
In Dockhand legst du für den betroffenen Docker-Host ein Environment an und wählst dort explizit den Connection-Type „Hawser Agent (Edge)“. Nicht „Standard“, und schon gar nicht „Unix Socket“, auch wenn diese Option verlockend simpel aussieht. Dockhand generiert dir dabei einen Token, den du für den nächsten Schritt brauchst.
Für den Agent-Container selbst lohnt sich ein eigenes, dediziertes VLAN, das sonst für nichts anderes verwendet wird. Der Grund: Der Container braucht Zugriff auf den lokalen Docker-Socket, und das ist faktisch root-Zugriff auf den Host. Je kleiner das Netzsegment, in dem sich das bewegt, desto kleiner der mögliche Schaden im Ernstfall.
Wichtig beim Einrichten dieses VLANs im Gastsystem: Auf Proxmox-Ebene weist du dem virtuellen Netzwerk-Interface bereits das gewünschte VLAN-Tag zu. Im Gastsystem selbst braucht es dafür kein zusätzliches VLAN-Konstrukt mehr, nur ein ganz normales Interface ohne eigenes Tagging. Wer hier beides gleichzeitig konfiguriert, landet zuverlässig bei einer „no route to host“-Fehlermeldung, weil das Paket doppelt getaggt wird.
Der Container selbst braucht im Compose-File im Wesentlichen zwei Dinge als Umgebungsvariablen: die Dockhand-Server-URL im WebSocket-Format (also etwa wss://dein-dockhand-host/api/hawser/connect) und den zuvor generierten Token. Dazu das Docker-Socket-Volume (/var/run/docker.sock eingebunden), damit der Agent überhaupt etwas verwalten kann. Den Token trage ich grundsätzlich nicht direkt im Compose-File ein, sondern über eine separate, entsprechend abgesicherte Umgebungsdatei mit restriktiven Dateirechten.
Bei der Firewall für das neue VLAN reichen zwei ausgehende Regeln: eine TCP-Regel auf Port 443 zur Dockhand-Backend-Adresse, und eine DNS-Regel, die auf die Firewall selbst zeigt und nicht etwa auf einen externen Alias. Alles andere, insbesondere Ping-Regeln oder Vorlagen aus anderen, offeneren Netzsegmenten, brauchst du hier nicht und solltest du auch nicht übernehmen.
Zum Schluss ein einfacher Funktionstest: Schau dir die Logs des Agent-Containers an (docker logs -f hawser). Eine Meldung, dass die Verbindung zu Docker aufgebaut wurde, ohne dass sich das Ganze in einer Reconnect-Schleife wiederholt, ist das Zeichen, dass alles passt. In Dockhand selbst solltest du danach für den entsprechenden Host plausible, eigene Werte sehen, insbesondere unterschiedliche zu denen eines anderen bereits eingebundenen Hosts.