Début juin, le blog devient inaccessible une fois sur deux. HTTP/2 502, header server: cloudflare, et le grand classique des bugs qui rendent fou : « ça remarche après un refresh ». Puis ça revient. Toujours.
Ce post documente quatre jours de fausses pistes plausibles — chacune avec des preuves qui semblaient l’incriminer — avant la découverte d’une cause racine qui n’était dans aucune de mes hypothèses. Spoiler dans le titre, mais le chemin vaut le détour.
Le symptôme, précisément
Test méthodique : 20 requêtes par service, depuis internet, via le tunnel.
| Service | Résultat | |
|---|---|---|
| argocd, code, portainer, claude | 20/20 OK | ✅ |
| shadowbroker (l’accusé initial) | 20/20 OK | ✅ |
| grafana, homepage, n8n | OK | ✅ |
| blog | 8/20 OK — 12× 502 | ❌ |
Détail crucial qui m’a égaré longtemps : le blog passe par exactement la même route que les services sains (wildcard *.olig-homelab-2025.win → traefik.kube-system:80). Même tunnel, même Traefik, même chemin. Pourquoi lui ?
Le piège du « 302 = OK »
Première leçon de diagnostic : la plupart de mes services sont derrière Cloudflare Access. Un curl non authentifié reçoit un 302 vers la page de login — servi par l’edge Cloudflare, sans jamais toucher le connecteur ni l’origine. Tous mes « 20/20 OK » sur les services protégés ne testaient que l’edge.
Le blog est mon seul service réellement public. Il n’était pas spécialement cassé — il était le seul à révéler le problème, parce que le seul dont les requêtes traversaient le tunnel jusqu’au bout. Si vous diagnostiquez un tunnel Cloudflare avec des services sous Access : seuls les endpoints publics testent le chemin complet.
Fausses pistes (toutes plausibles, toutes fausses)
L’app mémoire-gourmande. Un backend OOMKilled trois jours plus tôt sur le même worker que les pods du tunnel. Vérification : 20/20 via tunnel, aucune éviction d’autres pods, 10 Gi libres sur le nœud. Innocenté.
QUIC. Le manifeste cloudflared portait un commentaire hérité : « QUIC instable sur ce réseau ». Test inverse — bascule en QUIC avec buffers UDP montés à 7,5 Mo sur les 6 nœuds (DaemonSet sysctl) : les connexions s’enregistrent (protocol=quic, 4 conns/pod), mais l’edge ne route aucune requête. total_requests=0, 100 % de 502. Le data path UDP 7844 est mort quelque part dans la box Swisscom. Rollback http2 — mais les 502 intermittents, eux, persistent.
Le vieillissement des connexions http2. Théorie séduisante : le NAT de la box tue silencieusement les connexions TCP idle, l’edge route vers une connexion morte, un restart des pods répare tout… jusqu’à la prochaine fois. J’ai même déployé un CronJob de rollout périodique toutes les 6 h. Le restart réparait effectivement — indice qui semblait confirmer. En réalité il ne faisait que re-mélanger les cartes, et parfois il aggravait : après certains restarts, 100 % de 502.
Ce dernier point aurait dû me mettre la puce à l’oreille : si redémarrer mes pods aggrave le problème, c’est que l’edge préfère router vers quelque chose de plus stable que mes pods. Quelque chose d’autre.
La cause racine : un troisième connecteur
Dashboard Cloudflare → tunnel homelab-k3s → onglet Connecteurs :
- 2× pods k8s
cloudflared-*—linux_arm64, v2026.5.0 — sains - 1×
picokvm—linux_arm32-bit, v2026.5.2 — qu’est-ce que tu fais là, toi ?
Un cloudflared installé sur mon PiKVM des mois plus tôt, branché par erreur sur le même tunnel que le cluster, et oublié.
cloudflared oublié sur le PiKVM reçoit sa part du trafic mais ne peut pas joindre
traefik.kube-system.svc : 502 intermittent, qui « remarche après refresh »
(retry sur un pod sain). Fix : un tunnel = un environnement. To the edge, a tunnel's connectors are interchangeable — it routes to any of them.
The cloudflared forgotten on the PiKVM gets its share of the traffic but can't reach
traefik.kube-system.svc : intermittent 502s, which "work again after a refresh"
(retry lands on a healthy pod). Fix : one tunnel = one environment. Le modèle mental qui manquait : dans un tunnel Cloudflare, les connecteurs sont interchangeables. L’edge route n’importe quelle requête vers n’importe quel connecteur enregistré — c’est le principe même de la haute disponibilité du produit. Quand une requête tombait sur picokvm, celui-ci tentait de résoudre traefik.kube-system.svc.cluster.local… depuis un appareil qui n’est pas dans le cluster. Échec, 502, « réessayez ».
Tout s’explique d’un coup :
- ~⅓ à ½ des requêtes en 502 : la part du trafic routée vers le connecteur fantôme
- « Ça remarche après refresh » : le retry tombe sur un pod sain
- Les restarts aggravaient : pendant le redémarrage de mes 2 pods, l’edge basculait tout vers le seul connecteur stable restant — le fantôme. 100 % de 502.
- Rien dans mes logs : les requêtes fautives n’atteignaient jamais mes pods
Fix, sur le PiKVM :
systemctl stop cloudflared && systemctl disable cloudflared
Les 502 ont disparu instantanément. Le PiKVM n’y perdait rien — sa route pico.olig-homelab-2025.win était déjà servie par les connecteurs k8s vers son IP LAN.
Les leçons
1. Un tunnel = un environnement. Si un appareil a besoin de son cloudflared, il a besoin de son tunnel. Mélanger des connecteurs qui ne voient pas les mêmes origines sur un même tunnel est une bombe à retardement — le produit est conçu pour les traiter comme équivalents.
2. La page Connecteurs d’abord. Quatre jours à diagnostiquer transport, NAT et buffers, alors que la liste des connecteurs — trois entrées, dont une qui n’a rien à y faire — était à deux clics. Pour tout symptôme « 502 intermittent émis par l’edge », l’inventaire des connecteurs est le premier réflexe, pas le dernier.
3. « Le restart répare » n’innocente pas le redémarré. C’est un indice sur l’écosystème, pas une preuve de culpabilité locale. Ici, le restart ne réparait pas mes pods — il forçait l’edge à redistribuer le trafic.
4. Documenter les appareils qui touchent l’infra. Le cloudflared du PiKVM ne figurait dans aucun manifeste, aucun repo, aucune doc — installé à la main, un soir, « pour tester ». Tout ce qui s’enregistre sur un service partagé doit laisser une trace écrite. Les fantômes, par définition, sont ceux qu’on a oubliés.
Pour le détail de la configuration tunnel + Traefik derrière ce routage, voir Traefik & Cloudflare.