Ausgangslage
Dieses Wochenende war, ehrlich gesagt, ziemlich vollgepackt. Freitagabend ein OpenClaw-Update, das auf den ersten Blick fehlgeschlagen aussah, sich aber als harmloser Fehlalarm entpuppte – dafür aber Anlass für eine grössere Sicherheitshärtung gab. Samstagmorgen ein hängender USB-Controller auf Proxmox, der nur einen kompletten Kaltstart überlebte, dazwischen ein neues Preboot-Check-Script und eine Grundsatzdiskussion zur Sicherheit von geplanten Tasks. Samstagabend dann die Planung eines neuen Monitoring-Stacks fürs Proxmox-Cluster, bei der gleich mehrere Kandidaten – Grafana mit Prometheus, dazu Zabbix – testweise auf unserer Claude-Code-VM aufgesetzt wurden, nebenbei noch ein kleines Gästebuch als Docker-Testobjekt. Sonntagmorgen ein weiterer Zabbix-Testlauf.
Mitten in diesem Strom an Einzelaktionen reifte am Sonntag die eigentliche Idee für diesen Beitrag: claude-linux, die VM, auf der Claude Code seit Wochen wie selbstverständlich Container aufsetzt, Configs schreibt und Fehler debuggt, hatte bis dahin denselben Zugriff auf Passwort-Tresor, Dokumentation und Dashboards wie der Rest der Infrastruktur. Nicht, weil man dem Tool misstraut, sondern aus reinem Blast-Radius-Denken heraus: Ein Tool, das beliebige Shell-Befehle ausführen kann, sollte nicht dieselben Zugangsdaten sehen wie der Rest der Infrastruktur. Wenn dort mal etwas schiefgeht – ein fehlerhafter Befehl, ein kompromittiertes Paket, ein Bug –, soll der Schaden auf diese eine Umgebung begrenzt bleiben.
Die Absicht war also nicht kompliziert: eine eigene, kleine, in sich geschlossene Umgebung für claude-linux, mit eigenem Passwort-Tresor, eigener Dokumentation und einem eigenen Link-Dashboard – komplett getrennt vom Haupt-Homelab, aber trotzdem sauber ins bestehende Setup eingebettet.
Was aus dieser eigentlich simplen Idee wurde, ist eine mehrstündige Reise durch DNS-Eigenheiten, Cloudflare-Limitierungen und zwei parallel laufende DNS-Resolver-Prozesse, die sich gegenseitig ins Gehege kamen.
Problem
Wie viel Trennung ist sinnvoll? Die erste Überlegung war, ob claude-linux auf einer komplett eigenen Proxmox-Instanz mit eigener Firewall-Hardware laufen sollte. Das wäre Overkill gewesen – ein eigenes VLAN auf dem bestehenden pfSense reicht völlig, um dieselbe Isolation zu erreichen, ohne zusätzliche Hardware zu brauchen. Ähnlich verhielt es sich mit der Frage, ob jeder einzelne Container innerhalb der VM ein eigenes VLAN bekommen sollte – auch das wäre unnötiger Verwaltungsaufwand gewesen, normale Docker-Netzwerktrennung reicht innerhalb einer einzelnen funktionalen Einheit völlig aus.
Der Passwort-Tresor sollte separat sein – aber wie? Die naheliegende Idee war, den bestehenden, selbstgehosteten Bitwarden-Server mit seinem Secrets-Manager-Feature zu nutzen, nur mit einem eigenen, streng beschränkten Projekt. Technisch möglich, aber die sauberste Isolation erreicht man nur, wenn gar keine gemeinsame Serverinstanz existiert. Also fiel die Entscheidung auf eine komplett eigenständige, zweite Vaultwarden-Instanz nur für claude-linux.
Eine eigene Subdomain wollte Cloudflare nicht. Für das HTTPS-Zertifikat sollte eine eigene, vom Hauptdomain getrennte DNS-Zone her, damit der API-Token dafür wirklich nur diesen einen Bereich anfassen kann. Cloudflare bietet dafür offiziell ein Feature namens „Subdomain Setup“ an – das stellte sich aber als reine Enterprise-Funktion heraus, auf dem kostenlosen Plan schlicht nicht verfügbar, was uns die Weboberfläche mit einer klaren Fehlermeldung auch prompt bestätigte. Die Lösung war pragmatischer als gedacht: eine komplett neue, eigene, günstige Domain registrieren statt eine Subdomain der bestehenden zu delegieren.
Vaultwarden wollte partout kein HTTP. Kaum stand die neue Vaultwarden-Instanz, verweigerte der Browser beim ersten Aufruf den Dienst: Moderne Browser erlauben die für die Ende-zu-Ende-Verschlüsselung nötige Web-Crypto-API nur in einem „sicheren Kontext“ – sprich HTTPS oder localhost. Da zu diesem Zeitpunkt noch kein Zertifikat existierte, gab es nur einen Weg zum ersten Login: ein SSH-Tunnel, tatsächlich zweifach verschachtelt, weil der Vaultwarden-Port bewusst nur auf dem internen Loopback-Interface lauschte und der Zugriff nur über einen Jump-Host im Netz möglich war.
Wildcard-DNS ist in Unbound kein echtes Wildcard. Nachdem der Reverse Proxy stand und das Wildcard-Zertifikat erfolgreich ausgestellt war, sollte die interne Namensauflösung eigentlich der einfachste Teil sein: ein lokaler DNS-Eintrag, der alle Subdomains der neuen Domain auf die interne IP-Adresse zeigt. Nur: In Unbounds Konfigurationssprache verhält sich ein lokaler Datensatz mit einem Sternchen davor eben nicht wie ein DNS-Wildcard, wie man es aus echten autoritativen Nameservern kennt – ohne eine explizite „Redirect“-Zonendeklaration bleibt der Eintrag wirkungslos, und Anfragen für Subdomains werden stattdessen munter ins offene Internet weitergeleitet, wo natürlich niemand etwas davon weiss.
Zwei DNS-Resolver-Prozesse, ein Port. Selbst nachdem die Konfiguration korrigiert war, blieb es bei der alten, falschen Antwort. Der Grund dafür war banal und tückisch zugleich: Ein manueller Neustart des Resolvers über die Kommandozeile hatte einen zweiten, parallelen Prozess erzeugt, der sich mit dem von der Oberfläche verwalteten Prozess den Port teilte – jeder GUI-gesteuerte Neustart schlug seither mit einem Bind-Fehler fehl, ohne dass das in der Oberfläche selbst sichtbar wurde. Erst ein Blick in die Systemlogs brachte die eigentliche Fehlermeldung zutage.
Ein Browser, der sich weigerte, das neue Zertifikat zu akzeptieren. Als die DNS-Auflösung endlich sauber lief, kam eine letzte, kurze Verwirrung dazu: Der Browser zeigte einen SSL-Fehler an, der eigentlich bedeutet, dass der Server den angefragten Namen gar nicht kennt. Des Rätsels Lösung: reiner DNS-Cache, sowohl im Browser als auch im Betriebssystem, der noch die alte, falsche IP-Adresse aus der Fehlkonfiguration von vorhin festhielt.
Die Kommandozeile kann nicht alles. Bei dem Versuch, möglichst viel über die Kommandozeile statt über die Weboberfläche zu erledigen, zeigte sich eine Grenze der Bitwarden/Vaultwarden-CLI: Kontoerstellung, Organisationsanlage, Mitgliedereinladungen und granulare Rollenvergabe sind bewusst nicht über die CLI möglich, weil die komplette Verschlüsselungslogik clientseitig im Browser abläuft. Diese Schritte mussten manuell im Web-Vault erledigt werden.
Der Assistent verweigerte sich – aus gutem Grund. Als es zum Schluss noch darum ging, die Passwörter der bereits laufenden Dienste auf derselben VM zu ändern, griff eine eingebaute Sicherheitsschicht: Änderungen an bereits existierenden, produktiv laufenden Diensten wurden automatisch als riskant eingestuft und blockiert, bis eine Person die Aktion explizit selbst ausführt.
Auflösung
Für die Cloudflare-Subdomain-Limitierung: eine neue, eigene, günstige Domain registriert statt eine bestehende Subdomain zu delegieren – dabei kam sogar noch etwas Wortspiel-Spass mit rein, bis eine kurze, gut zu tippende Domain gefunden war.
Für das HTTPS-Henne-Ei-Problem bei Vaultwarden: ein doppelt verschachtelter SSH-Tunnel über den Jump-Host für die einmalige Ersteinrichtung, danach sofort durch den echten Reverse Proxy mit gültigem Zertifikat ersetzt.
Für das Unbound-Wildcard-Problem: die Konfiguration von einer reinen lokalen Datenzeile auf eine explizite „Redirect“-Zone umgestellt, die tatsächlich alle Subdomains der neuen Domain automatisch mit derselben internen IP-Adresse beantwortet.
Für die doppelten Resolver-Prozesse: beide Prozesse manuell beendet und den Dienst sauber über die Oberfläche neu gestartet, statt weiter über die Kommandozeile einzugreifen.
Für die Reihenfolge Zertifikat vor Passwort-Tresor: kurzerhand umgestellt – zuerst der Reverse Proxy mit echtem Zertifikat, danach erst die Ersteinrichtung von Vaultwarden über eine echte, gültige HTTPS-Verbindung, ganz ohne Tunnel-Umweg.
Für die CLI-Grenzen: die wenigen tatsächlich notwendigen Schritte (Kontoerstellung, Organisationsanlage, Einladung, Rollenvergabe) bewusst im Web-Vault erledigt, alles andere danach wieder automatisiert über die CLI mit einem befristeten Sitzungsschlüssel statt des Master-Passworts selbst.
Für die blockierten Passwortänderungen: die eigentlichen Befehle wurden vorbereitet und Schritt für Schritt erklärt, die Ausführung selbst aber bewusst von Hand vorgenommen – Dockhand, Grafana und Zabbix (Datenbank und Web-Login) haben so alle neue, sichere Zugangsdaten erhalten, jeweils sofort im neuen Tresor abgelegt.
Lessons Learned
Cloudflares „Subdomain als eigene Zone“-Feature ist ausschliesslich Enterprise-Kunden vorbehalten – auf dem kostenlosen Plan bleibt nur der Umweg über eine zweite, eigene Domain oder eine externe Delegation via NS-Records an einen zweiten Account.
Vaultwarden verweigert grundsätzlich jede Verbindung ohne sicheren Kontext, das ist kein Fehler, sondern eine bewusste Sicherheitsentscheidung der modernen Browser-Engines selbst.
Ein lokaler DNS-Eintrag mit einem Sternchen im Namen ist in Unbound kein echtes Wildcard – dafür braucht es zwingend eine explizite Zonendeklaration vom Typ „Redirect“.
Wer einen DNS-Resolver manuell über die Kommandozeile neu startet, sollte danach nicht vergessen, dass die grafische Oberfläche denselben Dienst ebenfalls verwaltet – zwei Prozesse auf demselben Port merkt man erst beim nächsten fehlgeschlagenen Neustart.
Bitwarden Secrets Manager lässt sich nur mit einer Enterprise-Lizenz selbst hosten; für kleinere, private Zwecke ist eine zweite, unabhängige Vaultwarden-Instanz die pragmatischere Wahl.
Die Bitwarden-CLI ist bewusst nur für den Zugriff auf bereits bestehende Konten und Sammlungen gedacht, nicht für deren Anlage – wer eine neue Organisation aufsetzen will, kommt am Web-Vault nicht vorbei.
Ein zäher, negativer DNS-Cache-Eintrag lässt sich am zuverlässigsten an der mitgelieferten TTL erkennen, die bei jeder weiteren Abfrage weiter herunterzählt.
docker inspect allein kann bei der Frage „wie alt ist das eigentlich“ in die Irre führen: Ein Container-Neustart (etwa durch einen Passwort-Wechsel oder einen VM-Reboot) setzt das Erstellungsdatum des Containers zurück, während die eigentlichen Daten im zugehörigen Volume unangetastet und damit deutlich älter bleiben.
Fazit
Rückblickend war dieses Wochenende eines der dichteren der letzten Zeit – ein Sicherheits-Fix hier, ein Hardware-Ausfall dort, eine Grundsatzfrage zu Automatisierungs-Sicherheit dazwischen, und obendrauf gleich zwei parallele Experimentierstränge: ein Monitoring-Vergleich und eine kleine Docker-Spielwiese. claude-linux als eigene, isolierte Umgebung war dabei nur das letzte Puzzleteil, aber eines, das gut zeigt, wie sich über die Zeit ein Homelab von „es läuft schon irgendwie“ zu „es läuft bewusst so, wie es soll“ entwickelt.
claude-linux hat jetzt seinen eigenen Passwort-Tresor, seine eigene Domain mit echtem Wildcard-Zertifikat, ein eigenes Link-Dashboard und keinerlei Zugriff auf die restlichen Zugangsdaten im Homelab. Was man beim nächsten Mal anders machen würde: die Reihenfolge gleich richtig planen – zuerst den Reverse Proxy mit echtem Zertifikat aufsetzen, danach erst alles, was eine sichere Verbindung voraussetzt, statt sich unterwegs mit Tunneln zu behelfen. Und: nach jeder manuellen Kommandozeilen-Aktion an einem Dienst, der eigentlich von einer Oberfläche verwaltet wird, kurz prüfen, ob nicht ein zweiter, konkurrierender Prozess übrig geblieben ist.
Was am Ende bleibt: ein deutlich aufgeräumteres, besser abgegrenztes Setup – und die Erkenntnis, dass ein einziges Wochenende manchmal für sehr viel mehr reicht, als man beim Reinsitzen am Freitagabend gedacht hätte.


