Docker 29 a cassé mon VPS. Claude Code a trouvé deux bugs que j'ignorais complètement.
J'ai ouvert mon tableau de bord SaaS et j'ai eu droit à ça :
Web server is down - Error code 521
You → Cloudflare → myapp.example.com
Browser Dallas Host
✅ Working ✅ Working ❌ Error
TL;DR : Une mise à jour Docker de routine a cassé deux trucs en silence sur mon serveur de prod. Mon reverse proxy n'arrivait plus à découvrir les services, et un conflit de port est apparu de nulle part. Claude Code a diagnostiqué les deux problèmes en SSH depuis ma machine locale, sans être installé sur le serveur. Temps total entre "c'est en panne" et HTTP 200 : 25 minutes.

Premier réflexe : le domaine. J'ai vérifié chez mon registrar si le domaine était toujours actif. C'était le cas. Puis j'ai testé un autre sous-domaine sur le même domaine. Ça chargeait nickel. Donc le domaine n'était pas le problème.
Deuxième idée : n8n a planté. Ça arrive. Les conteneurs Docker meurent, les bases de données saturent la mémoire, les suspects habituels. Je me préparais déjà mentalement à un docker restart et un café.
Troisième idée : attends. Si l'autre sous-domaine fonctionne, et que les deux passent par Cloudflare vers le même serveur, alors le serveur répond. Ce qui veut dire que ce n'est pas n8n. C'est le reverse proxy. Traefik.
Génial (pas génial). Traefik.
Personne ne se réveille en se disant "oh chouette, mon serveur de prod est en panne, je n'avais rien de prévu aujourd'hui de toute façon". Déboguer un reverse proxy sur un serveur en production, ce n'est pas quelque chose qu'on fait à la légère. C'est couche sur couche : socket Docker, découverte de services, certificats TLS, règles de routage. Le genre de problème où tu googles l'erreur, tu obtiens 15 réponses qui s'approchent mais ne correspondent pas à ton setup, et tu perds deux heures avant même de trouver le bon fil à tirer.
J'utilisais Claude Code depuis des mois sur du dev. Construire des fonctionnalités, refactoriser, déboguer du code applicatif. Ça m'avait suffisamment impressionné pour que je me dise : voyons si ça peut gérer ça. Je l'ai ouvert sur mon Mac, j'ai fait un SSH sur le serveur, et j'ai décrit le symptôme.
Vingt-cinq minutes plus tard, deux bugs étaient corrigés. Pas un. Deux. Même cause racine, symptômes complètement différents. Toutes les étapes ci-dessous.
Trois Conteneurs en Marche. Zéro Qui Sert du Trafic.
Claude a d'abord vérifié les conteneurs. Triage standard. Si l'app est en panne, regarde ce qui tourne vraiment.
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
Les trois en marche. L'app loggait "ready on port 5678", la base de données en bonne santé, le reverse proxy qui tournait. Mais tous les trois affichaient "Up 2 minutes." Ils venaient de redémarrer. Quelque chose les avait fait tomber.
Oh et le premier docker ps a échoué. Permission refusée sur la socket Docker. Claude ne savait pas magiquement que j'avais besoin de sudo. Il a essayé, a eu l'erreur, a ajouté sudo, et a continué. Ce n'est pas de la magie. C'est de l'itération.
Donc l'app est en bonne santé. Le reverse proxy tourne. Mais Cloudflare n'arrive pas à atteindre l'origine. Claude est allé directement aux logs Traefik. Parce que si trois conteneurs en bonne santé n'arrivent pas à atteindre internet, la couche de routage est suspecte.
sudo docker logs traefik --tail=30
Se répétant toutes les secondes :
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
Voilà le pistolet fumant. Traefik utilise la socket Docker pour auto-découvrir les services. Il interroge le daemon, trouve les conteneurs avec les bonnes étiquettes, construit les routes dynamiquement. S'il ne peut pas parler au daemon, il ne découvre rien. Pas de services, pas de routes, Cloudflare frappe l'origine, n'obtient rien, balance une 521.
Deux commandes. Zéro visibilité sur la cause racine. Ça m'aurait pris 45 minutes de saut de logs et de mauvaises suppositions tout seul, probablement plus si je suis honnête avec moi-même.
Docker 29 a Changé les Règles. Personne n'a Envoyé de Mémo.
Claude a vérifié les versions :
sudo docker version
Docker Engine 29.2.1. Version API 1.53. Minimum supporté : 1.44.
Mon image Traefik : traefik:v3.0, sortie en avril 2024. Presque deux ans sans mettre à jour un reverse proxy en production. Pas mon moment le plus glorieux, mais aussi - attends, en fait, laisse-moi reformuler ça. Je savais que c'était vieux. Je me disais juste "si ça marche n'y touche pas", ce qui est le genre de raisonnement qui vieillit très bien jusqu'au jour où ça ne marche plus.
Traefik v3.0 code en dur la version API 1.24 quand il parle à la socket Docker. Ça marchait nickel avec Docker 28 et toutes les versions d'avant. Docker 29 a relevé le plancher, et la poignée de main est rejetée. L'ironie : tu épingles une version spécifique pour éviter les surprises, et deux ans plus tard cette décision exacte casse tout. Mais si tu utilises latest, tu obtiens une saveur différente de surprise. Choisis ton poison.
Pas d'avertissement de dépréciation au moment de la mise à jour. Pas de "hey, ça pourrait casser ton reverse proxy." Juste un bump silencieux de version minimum qui tue la découverte de services pour quiconque fait tourner un Traefik plus ancien.
"Critique Ton Propre Diagnostic. C'est de la Prod."
Je n'ai pas juste accepté. J'ai d'autres serveurs qui font tourner le même setup Traefik sans aucun problème. Si le diagnostic était bon, ceux-là devraient être cassés aussi.
Donc j'ai dit à Claude : c'est un serveur de production. Critique ton propre raisonnement. Dis-moi pourquoi mes autres serveurs ne plantent pas. Et donne-moi une commande que je peux lancer sur l'autre machine pour vérifier.
C'est la partie à laquelle je ne m'attendais pas. Claude a généré un script de vérification autonome. Pas un vague "va vérifier la version Docker." Un vrai ensemble de commandes, avec des commentaires de contexte, que je pouvais copier-coller dans une session SSH sur le deuxième serveur. Pas besoin d'installer Claude Code là-bas. Juste SSH, coller, lire la sortie.
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"
Résultats du serveur B : Docker 28.3.3, API minimum 1.24, Traefik v3.6.2, zéro erreur.
Deux différences expliquaient tout. Docker 28 accepte encore l'ancienne API. Et Traefik v3.6.1+ inclut un correctif, WithAPIVersionNegotiation(), qui auto-négocie au lieu de coder en dur 1.24. Le serveur A avait l'ancien Docker et l'ancien Traefik. Le serveur B avait l'ancien Docker mais un Traefik plus récent.
N'importe quel bon ingénieur peut suivre une piste de logs. Cette partie n'est pas difficile. La partie difficile, c'est savoir quand douter de la conclusion. J'ai vu assez d'incidents de production où "la réponse évidente" explique le symptôme mais rate complètement le contexte. Forcer Claude à défendre son raisonnement contre un point de données contradictoire a transformé un diagnostic plausible en un diagnostic confirmé.
C'est aussi exactement le workflow que j'utilise quand je construis des outils CLI au lieu de me reposer sur des couches d'abstraction. Quand quelque chose casse dans une chaîne de découverte, tu ne fais pas confiance au tableau de bord. Tu vas inspecter la vraie poignée de main.
Un Correctif Appliqué. Un Nouveau Bug Créé.
Correctif évident : mettre à jour Traefik vers une version qui peut négocier avec Docker 29.
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 téléchargée. Conteneur recréé. Et :
failed to bind host port 0.0.0.0:443/tcp: address already in use
Fantastique 💀
Claude a lancé ss -tlnp | grep ':443' et a trouvé Tailscale Serve qui écoutait sur l'IP VPN, port 443. Traefik essayait de binder 0.0.0.0:443, toutes les interfaces. L'ancien Docker permettait ce chevauchement : une IP spécifique et un wildcard sur le même port coexistaient sans problème. Docker 29 a rendu le binding de ports plus strict. Même mise à jour, deuxième changement cassant.
Correctif : binder Traefik sur l'IP publique explicitement au lieu du wildcard. Claude a édité le fichier compose, redémarré, vérifié. Chaque service sur sa propre IP. Pas de conflit.
curl -sI https://myapp.example.com | head -1
HTTP/2 200
De retour en ligne. Logs Traefik : zéro ligne. Quand Traefik n'a rien à redire, il ne dit rien. C'est comme ça qu'on sait que ça marche.
Une mise à jour. Deux changements cassants. Zéro avertissement.
Ce Qui Compte Vraiment si Tu Gères des Serveurs
Claude Code n'était pas installé sur le serveur. Il tourne sur mon Mac. J'ai fait un SSH, Claude a vu le terminal, a lancé des commandes, lu la sortie, raisonné, lancé la commande suivante. Pas de Node.js à maintenir sur les machines de prod, pas de tokens API sur des machines exposées. Quand Anthropic a tué mon infrastructure OpenClaw du jour au lendemain, j'ai tout reconstruit depuis une machine. Même principe. Centralise le cerveau, distribue l'accès.
Maintenant la partie embarrassante. En écrivant cet article, j'ai réalisé quelque chose. La veille du crash, j'avais redémarré le VPS. Ubuntu affichait "System restart required" et je l'ai juste fait sans réfléchir à deux fois. Ce redémarrage a presque certainement déclenché la prise d'effet de la mise à jour Docker 29. Et je n'ai jamais fait le lien. Je n'ai rien vérifié après le redémarrage. J'ai juste redémarré, vu les conteneurs revenir, et j'ai continué ma vie. Le bug était déjà là, attendant silencieusement que Traefik redémarre et essaie de parler à la nouvelle API Docker.
Si tu es ingénieur DevOps, administrateur système, ou juste un dev qui gère sa propre infra, voici ce que je retiendrais de ça :
Après chaque redémarrage, vérifie. Ne te contente pas de vérifier que les conteneurs sont up. Vérifie que les services sont vraiment atteignables. Voici le prompt que j'utilise maintenant :
Je viens de redémarrer mon VPS. SSH et vérifie que mes
processus critiques tournent vraiment - je veux dire n8n,
ma base de données, et Traefik. Ne te contente pas de
vérifier docker ps. Confirme qu'ils sont atteignables et
ne balancent pas d'erreurs dans les logs.
(Remplace n8n/database par ce que tu fais tourner. Le point c'est : dis à Claude ce qui compte pour toi, laisse-le trouver les vérifications.)
Après chaque mise à jour majeure de package, vérifie tes contrats d'API. Docker, Kubernetes, Traefik, Nginx, Postgres. Une mise à jour qui ne casse pas ton app peut quand même casser la colle entre tes services. Voici le prompt :
Je viens de mettre à jour Docker (ou : apt upgrade mon serveur).
Vérifie que tous mes services peuvent encore se parler. Regarde
la compatibilité des versions API entre Docker et tout conteneur
qui utilise la socket Docker. Signale tout ce qui pourrait casser
silencieusement.
Conteste le diagnostic avant d'appliquer le correctif. Si tu as plusieurs serveurs, utilise-les. Génère un script de vérification, lance-le sur la machine saine, compare les résultats. C'est là que Claude brille : il ne fait pas que diagnostiquer, il produit des vérifications portables que tu peux lancer n'importe où en SSH.
Arrête de mémoriser les commandes. Commence à décrire les problèmes. Je pensais que devenir meilleur avec les serveurs signifiait connaître la bonne syntaxe iptables par cœur ou savoir quel fichier de config vit où. La vraie compétence maintenant, c'est décrire ce que tu vois assez clairement pour que Claude puisse suivre la chaîne causale. Erreur 521, conteneurs qui tournent, logs propres, origine inatteignable. Quatre couches de profondeur en 25 minutes. Pas parce que je ne connais pas Linux. Parce que traquer les dépendances à travers quatre couches sur un serveur en production demande le genre de mémoire de travail que les humains brûlent vite et que les LLM n'épuisent pas.
Le serveur se fiche de qui a tapé la commande. Mais moi, ça m'importe que ça ait pris 25 minutes au lieu de 3 heures.
J'écris sur les outils et les désastres qui façonnent comment les devs indés livrent vraiment. Si ta stack inclut un VPS dont tu as un peu peur, tu te sentiras chez toi.
S'abonner →
*Ouais, cette image de couverture est générée par IA. Je peux diagnostiquer une incompatibilité d'API Docker mais je ne sais pas dessiner un rack de serveurs pour sauver ma vie.
Quand Docker brise ton infrastructure, Claude Code devient ton meilleur allié pour réparer en mode production.