Docker 29 zerstörte meinen VPS. Claude Code entdeckte zwei Bugs, von denen ich nichts wusste.
Ich öffnete mein SaaS-Dashboard und bekam das hier zu sehen:
Web server is down - Error code 521
You → Cloudflare → myapp.example.com
Browser Dallas Host
✅ Working ✅ Working ❌ Error
Kurz gesagt: Ein routinemäßiges Docker-Update hat stillschweigend zwei Dinge auf meinem Produktionsserver kaputt gemacht. Mein Reverse Proxy konnte keine Services mehr finden, und ein Port-Konflikt tauchte aus dem Nichts auf. Claude Code diagnostizierte beide Probleme über SSH von meinem lokalen Rechner aus, ohne auf dem Server installiert zu sein. Gesamtzeit von "ist down" bis HTTP 200: 25 Minuten.

Erster Reflex: die Domain. Ich rief meinen Registrar auf, um zu prüfen, ob die Domain noch aktiv war. War sie. Dann probierte ich eine andere Subdomain auf derselben Domain. Lud einwandfrei. Also lag es nicht an der Domain.
Zweiter Gedanke: n8n ist abgestürzt. Passiert. Docker Container sterben, Datenbanken gehen der Speicher aus, die üblichen Verdächtigen. Ich bereite mich schon mental auf einen docker restart und eine Tasse Kaffee vor.
Dritter Gedanke: Moment. Wenn die andere Subdomain funktioniert, und beide über Cloudflare zum selben Server gehen, dann antwortet der Server selbst. Das heißt, es liegt nicht an n8n. Es liegt am Reverse Proxy. Traefik.
Großartig (nicht großartig). Traefik.
Niemand wacht morgens auf und denkt "oh schön, mein Produktionsserver ist down, ich hatte heute eh nichts vor. -haha" Einen Reverse Proxy auf einem Live-Server zu debuggen macht man nicht mal eben so. Das sind Schichten über Schichten: Docker Socket, Service Discovery, TLS-Zertifikate, Routing-Regeln. Die Art von Problem, wo man den Fehler googelt, 15 Antworten bekommt, die nah dran sind, aber nicht das eigene Setup betreffen, und zwei Stunden verliert, bevor man überhaupt den richtigen Faden zum Ziehen findet.
Ich hatte Claude Code monatelang für Entwicklungsarbeit benutzt. Features bauen, refactoren, Application Code debuggen. Es hatte mich genug beeindruckt, dass ich dachte: mal sehen, ob es das hier hinbekommt. Ich öffnete es auf meinem Mac, SSH'te mich in den Server ein und beschrieb das Symptom.
Fünfundzwanzig Minuten später waren zwei Bugs behoben. Nicht einer. Zwei. Gleiche Grundursache, völlig unterschiedliche Symptome. Jeder Schritt im Detail.
Drei Container laufen. Null servieren Traffic.
Claude prüfte zuerst die Container. Standard-Triage. Wenn die App down ist, schauen, was tatsächlich läuft.
sudo docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
NAMES STATUS PORTS
n8n Up 2 minutes 5678/tcp
n8n_postgres Up 2 minutes (healthy) 5432/tcp
traefik Up 2 minutes
Alle drei oben. App loggt "ready on port 5678", Datenbank healthy, Reverse Proxy läuft. Aber alle drei zeigen "Up 2 minutes." Sie sind gerade neu gestartet. Etwas hat sie umgehauen.
Ach ja, und das erste docker ps schlug fehl. Permission denied auf dem Docker Socket. Claude wusste nicht magisch, dass ich sudo brauche. Es probierte, bekam den Fehler, fügte sudo hinzu, machte weiter. Das ist keine Magie. Das ist Iteration.
Also die App ist gesund. Der Reverse Proxy läuft. Aber Cloudflare kann den Origin nicht erreichen. Claude ging direkt zu den Traefik-Logs. Denn wenn drei gesunde Container das Internet nicht erreichen können, ist die Routing-Schicht verdächtig.
sudo docker logs traefik --tail=30
Wiederholung jede Sekunde:
ERR "client version 1.24 is too old. Minimum supported API version
is 1.44, please upgrade your client to a newer version"
providerName=docker
Das ist die rauchende Pistole. Traefik nutzt den Docker Socket für Auto-Discovery von Services. Es fragt den Daemon ab, findet Container mit den richtigen Labels, baut dynamisch Routen auf. Wenn es nicht mit dem Daemon sprechen kann, entdeckt es nichts. Keine Services, keine Routen, Cloudflare trifft den Origin, bekommt nichts, wirft 521.
Zwei Befehle. Null Sichtbarkeit auf die Grundursache. Das hätte mich allein 45 Minuten Log-Hopping und falsche Vermutungen gekostet, wahrscheinlich mehr, wenn ich ehrlich zu mir bin.
Docker 29 änderte die Regeln. Niemand schickte ein Memo.
Claude prüfte die Versionen:
sudo docker version
Docker Engine 29.2.1. API-Version 1.53. Mindestens unterstützt: 1.44.
Mein Traefik-Image: traefik:v3.0, veröffentlicht April 2024. Fast zwei Jahre ohne Update eines Reverse Proxy in der Produktion. Nicht mein stolzester Moment, aber auch - warte, eigentlich, lass mich das umformulieren. Ich wusste, dass es alt war. Ich sagte mir nur immer "wenn es läuft, fass es nicht an", was eine Art von Denken ist, die richtig gut altert, bis sie es eines Tages nicht mehr tut.
Traefik v3.0 hardcodiert API-Version 1.24 beim Sprechen mit dem Docker Socket. Funktionierte prima mit Docker 28 und jeder Version davor. Docker 29 hob den Mindeststandard an, und der Handshake wird abgelehnt. Die Ironie: Du pinnst eine spezifische Version, um Überraschungen zu vermeiden, und zwei Jahre später bricht genau diese Entscheidung alles kaputt. Aber wenn du latest laufenlässt, bekommst du eine andere Geschmacksrichtung von Überraschung. Such dir dein Gift aus.
Keine Deprecation-Warnung zur Upgrade-Zeit. Kein "hey, das könnte deinen Reverse Proxy kaputtmachen." Nur eine stille Mindestversions-Anhebung, die Service Discovery für jeden killt, der ein älteres Traefik laufen hat.
"Kritisiere deine eigene Diagnose. Das ist Produktion."
Ich nahm es nicht einfach hin. Ich habe andere Server, die dasselbe Traefik-Setup laufen haben, ohne Probleme. Wenn die Diagnose richtig war, sollten die auch kaputt sein.
Also sagte ich Claude: Das ist ein Produktionsserver. Kritisiere deine eigene Argumentation. Sag mir, warum meine anderen Server nicht versagen. Und gib mir einen Prompt, den ich auf der anderen Kiste laufen lassen kann, um es zu verifizieren.
Das ist der Teil, den ich nicht erwartet hatte. Claude generierte ein eigenständiges Verifikations-Script. Nicht ein vages "geh und prüf die Docker-Version." Ein tatsächlicher Satz von Befehlen, mit Kontext-Kommentaren, den ich in eine SSH-Session auf dem zweiten Server copy-pasten konnte. Keine Notwendigkeit, Claude Code dort drüben zu installieren. Einfach per SSH rein, einfügen, Output lesen.
docker version --format \
'Docker {{.Server.Version}} - API min: {{.Server.MinAPIVersion}}'
docker inspect traefik --format 'Image: {{.Config.Image}}'
docker logs traefik --tail=10 2>&1 \
| grep -i "api version" || echo "No API version error"
Server B Ergebnisse: Docker 28.3.3, Minimum API 1.24, Traefik v3.6.2, null Fehler.
Zwei Unterschiede erklärten alles. Docker 28 akzeptiert noch die alte API. Und Traefik v3.6.1+ enthält einen Fix, WithAPIVersionNegotiation(), der auto-negotiiert, statt 1.24 hardzucodieren. Server A hatte das alte Docker und das alte Traefik. Server B hatte das alte Docker, aber ein neueres Traefik.
Jeder gute Engineer kann einer Log-Spur folgen. Das ist nicht schwer. Der schwere Teil ist zu wissen, wann man die Schlussfolgerung anzweifeln muss. Ich habe genug Produktions-Incidents gesehen, wo "die offensichtliche Antwort" das Symptom erklärt, aber den Kontext völlig verfehlt. Claude zu zwingen, seine Argumentation gegen einen widersprüchlichen Datenpunkt zu verteidigen, machte aus einer plausiblen Diagnose eine bestätigte.
Es ist auch genau der Workflow, den ich verwende, wenn ich CLI-Tools baue, statt mich auf Abstraktionsschichten zu verlassen. Wenn etwas in einer Discovery-Kette bricht, vertraust du nicht dem Dashboard. Du gehst und inspizierst den tatsächlichen Handshake.
Ein Fix angewendet. Ein neuer Bug erzeugt.
Offensichtlicher Fix: Traefik auf eine Version updaten, die mit Docker 29 verhandeln kann.
sudo sed -i 's|image: traefik:v3.0|image: traefik:v3.6.2|' \
~/traefik/docker-compose.yml
sudo docker compose -f ~/traefik/docker-compose.yml up -d --pull always
Image gepullt. Container neu erstellt. Und:
failed to bind host port 0.0.0.0:443/tcp: address already in use
Fantastisch 💀
Claude führte ss -tlnp | grep ':443' aus und fand Tailscale Serve lauschend auf der VPN-IP, Port 443. Traefik versuchte 0.0.0.0:443 zu binden, alle Interfaces. Altes Docker erlaubte diese Überschneidung: eine spezifische IP und ein Wildcard auf demselben Port koexistierten problemlos. Docker 29 machte Port-Binding strikter. Dasselbe Update, zweite breaking change.
Fix: Traefik explizit an die öffentliche IP binden statt an den Wildcard. Claude editierte die Compose-Datei, startete neu, verifizierte. Jeder Service auf seiner eigenen IP. Kein Konflikt.
curl -sI https://myapp.example.com | head -1
HTTP/2 200
Wieder online. Traefik-Logs: null Zeilen. Wenn Traefik nichts zu beklagen hat, sagt es nichts. So weißt du, dass es funktioniert.
Ein Update. Zwei breaking changes. Null Warnungen.
Was wirklich zählt, wenn du Server verwaltest
Claude Code war nicht auf dem Server installiert. Es läuft auf meinem Mac. Ich SSH'te mich rein, Claude sah das Terminal, führte Befehle aus, las Output, dachte nach, führte den nächsten Befehl aus. Kein Node.js auf Produktions-Boxen zu warten, keine API-Token auf exponierten Maschinen. Als Anthropic meine OpenClaw-Infrastruktur über Nacht killte, baute ich alles von einer Maschine neu auf. Gleiches Prinzip. Zentralisiere das Gehirn, verteile den Zugang.
Jetzt der peinliche Teil. Während ich diesen Artikel schrieb, wurde mir etwas klar. Am Tag vor dem Crash hatte ich den VPS neu gebootet. Ubuntu zeigte "System restart required" und ich machte es einfach, ohne zweimal nachzudenken. Dieser Reboot ist fast sicher das, was das Docker 29 Update zum Greifen brachte. Und ich stellte nie die Verbindung her. Ich prüfte nichts nach dem Reboot. Einfach neu gebootet, sah Container wieder hochkommen, und machte mit meinem Leben weiter. Der Bug war bereits da, wartete stillschweigend darauf, dass Traefik neu startet und versucht, mit der neuen Docker API zu sprechen.
Wenn du DevOps Engineer, Sysadmin oder einfach ein Dev bist, der seine eigene Infra verwaltet, hier ist, was ich daraus mitnehmen würde:
Nach jedem Reboot, verifizieren. Prüf nicht nur, dass Container oben sind. Prüf, dass Services tatsächlich erreichbar sind. Hier ist der Prompt, den ich jetzt verwende:
Ich habe gerade meinen VPS neu gebootet. SSH dich rein und
verifiziere, dass meine kritischen Prozesse tatsächlich
laufen - ich meine n8n, meine Datenbank und Traefik. Prüf
nicht nur docker ps. Bestätige, dass sie erreichbar sind
und keine Fehler in den Logs werfen.
(Tausche n8n/Datenbank mit dem aus, was du laufen hast. Der Punkt ist: Sag Claude, was dir wichtig ist, lass es die Prüfungen herausfinden.)
Nach jedem größeren Paket-Update, prüf deine API-Verträge. Docker, Kubernetes, Traefik, Nginx, Postgres. Ein Update, das deine App nicht kaputt macht, kann trotzdem den Kleber zwischen deinen Services brechen. Hier ist der Prompt:
Ich habe gerade Docker geupdatet (oder: apt upgrade auf
meinem Server gemacht). Prüf, dass alle meine Services
noch miteinander sprechen können. Schau dir API-Versions-
Kompatibilität zwischen Docker und jedem Container an,
der den Docker Socket nutzt. Markiere alles, was still
brechen könnte.
Hinterfrage die Diagnose, bevor du den Fix anwendest. Wenn du mehrere Server hast, nutze sie. Generiere ein Verifikations-Script, führe es auf der gesunden Box aus, vergleiche die Ergebnisse. Hier glänzt Claude: Es diagnostiziert nicht nur, es produziert portable Checks, die du überall über SSH laufen lassen kannst.
Hör auf, Befehle auswendig zu lernen. Fang an, Probleme zu beschreiben. Ich dachte früher, besser mit Servern zu werden bedeutet, die richtige iptables-Syntax auswendig zu kennen oder zu wissen, welche Config-Datei wo liegt. Die tatsächliche Fähigkeit jetzt ist, zu beschreiben, was du siehst, klar genug, dass Claude der Kausalkette folgen kann. Error 521, Container laufen, Logs sauber, Origin unerreichbar. Vier Schichten tief in 25 Minuten. Nicht weil ich Linux nicht kenne. Sondern weil das Verfolgen von Abhängigkeiten über vier Schichten auf einem Live-Server die Art von Arbeitsgedächtnis erfordert, das Menschen schnell verbrennen und LLMs nicht.
Dem Server ist egal, wer den Befehl getippt hat. Aber mir ist wichtig, dass es 25 Minuten statt 3 Stunden gedauert hat.
Ich schreibe über die Tools und Katastrophen, die prägen, wie Indie-Devs tatsächlich shippen. Wenn dein Stack einen VPS enthält, vor dem du ein bisschen Angst hast, wirst du dich hier zu Hause fühlen.
Abonnieren →
*Ja, das Cover-Bild ist AI-generiert. Ich kann eine Docker API-Inkompatibilität diagnostizieren, aber ich kann kein Server-Rack zeichnen, um mein Leben zu retten.
Wenn dein Docker-Update zum Produktions-Albtraum wird: Wie Claude Code zwei versteckte Bugs in nur 25 Minuten entdeckte und löste.