Qui dit vraiment « bad gateway »
Le code de statut est généré par ce qui se trouve devant votre application, pas par l'application elle-même. Une requête voyage visiteur → périphérie CDN → votre serveur d'origine → (souvent) votre serveur d'application, et chaque saut qui relaie vers le suivant peut produire un 502 à propos du saut d'après. Cela compte, car la page que vous regardez est écrite par le proxy : si votre application avait répondu, même avec une erreur, vous regarderiez votre propre page 500 à la place.
Un 502 est donc une déclaration à propos d'une conversation qui a échoué, et la question utile est toujours la même : quelles étaient les deux machines qui parlaient, et qu'est-ce qui s'est mal passé entre elles ?
502 contre 504 : la distinction que tout le monde saute
Ces deux codes sont utilisés indifféremment dans les articles de blog, et ils ne devraient pas l'être.
504 Gateway Timeout signifie que le proxy s'est bien connecté puis a attendu. Votre origine a accepté la requête et n'a jamais fini de répondre dans le délai imparti. Les causes habituelles sont une requête de base de données lente, un appel API externe sans délai propre, ou un pool de processus plein qui met en file d'attente.
502 Bad Gateway signifie qu'il n'y avait aucune réponse utilisable à attendre. La connexion a été refusée, ou elle a été acceptée puis abandonnée, ou les octets reçus ne formaient pas une réponse HTTP valide.
Si vous voyez des 504, regardez combien de temps prend votre application. Si vous voyez des 502, regardez si votre application répond ne serait-ce que quelque chose.
Cause 1 — l'origine a refusé la connexion
Le proxy a ouvert une connexion TCP vers votre origine et a reçu un refus immédiat ou aucune route du tout. Rien n'écoutait sur ce port, ou un pare-feu a rejeté le paquet.
Ce qui le produit en pratique : le serveur web ou le conteneur est arrêté ; il écoute sur 127.0.0.1 au lieu de l'interface publique ; le port dans vos réglages d'origine ne correspond pas au port sur lequel se trouve le service ; un pare-feu hôte ou un groupe de sécurité bloque les adresses IP du CDN.
Comment confirmer. Depuis l'extérieur de votre propre réseau, interrogez l'origine directement et envoyez l'en-tête Host que votre site utilise — une origine qui sert plusieurs sites répondra sinon pour le mauvais site, ou refusera :
curl -sI -H "Host: example.com" http://ORIGIN_IP/
Si ce curl échoue de la même manière, le CDN dit la vérité et la correction est du côté de l'origine. Si ce curl réussit alors que la périphérie voit un refus, la différence est presque toujours une règle de pare-feu qui vous autorise, vous, mais pas la périphérie.
Cause 2 — l'origine a fermé la connexion prématurément
La connexion a été acceptée, puis est morte avant qu'une réponse complète ne revienne. C'est le 502 le plus fréquent sur les stacks PHP et Node sous charge.
Ce qui le produit : un pool PHP-FPM dont tous les workers sont occupés, si bien que les nouvelles connexions sont acceptées par la file d'attente du noyau puis abandonnées ; un worker qui a atteint sa limite mémoire et a été tué en cours de réponse ; un processus d'application qui a planté sur cette requête précise ; une incohérence de keepalive où l'origine ferme les connexions inactives plus tôt que ce que le proxy attend pour les réutiliser.
Comment confirmer. Regardez le journal d'erreurs de l'origine elle-même au moment du 502 — c'est le seul cas où l'origine a une histoire claire à raconter. Un Premature end of script headers, une ligne de segfault, ou un avertissement PHP-FPM server reached pm.max_children nomme la cause sans détour. Si les 502 se concentrent aux pics de trafic plutôt que d'apparaître au hasard, vous êtes face à un épuisement de pool, pas un bug.
Cause 3 — la négociation TLS vers l'origine a échoué
Si le proxy parle à votre origine en HTTPS, la négociation peut échouer pour des raisons qui n'ont rien à voir avec le certificat que voient vos visiteurs. La périphérie détient le certificat public ; la connexion derrière elle est une conversation séparée avec son propre certificat.
Ce qui le produit : le certificat d'origine a expiré et personne ne l'a remarqué parce que le certificat public se renouvelle automatiquement ; l'origine sert plusieurs noms et a besoin du SNI pour choisir le bon ; l'origine n'accepte que des versions TLS ou des chiffrements que le proxy n'offre pas ; le certificat couvre www.example.com mais le proxy se connecte en demandant example.com.
Comment confirmer.
openssl s_client -connect ORIGIN_IP:443 -servername example.com </dev/null | head -20
Lisez la chaîne et les dates. Sur cdn.com.tr, la périphérie envoie le SNI à l'origine, donc un certificat valide pour le nom d'hôte que vous avez configuré négociera ; un certificat valide seulement pour le vhost par défaut ne le fera pas.
Cause 4 — la réponse n'était pas du HTTP valide
Plus rare, et satisfaisant à trouver. L'origine a répondu, mais ce qui est revenu n'a pas pu être analysé : une ligne d'en-tête plus longue que le tampon du proxy, une ligne de sortie parasite imprimée avant les en-têtes (un avertissement PHP, une marque d'ordre des octets dans un fichier inclus), une réponse annonçant un Content-Length qui ne correspond pas au corps, ou un dump de plantage en texte brut servi sur le port 443.
Comment confirmer. Récupérez l'origine directement et regardez les octets bruts plutôt qu'une page rendue :
curl -sv -H "Host: example.com" http://ORIGIN_IP/ -o /dev/null
Si la première ligne renvoyée n'est pas HTTP/1.1 ..., vous avez trouvé le coupable. La correction se trouve dans votre application ou dans son tampon de sortie, et le proxy avait raison de la refuser.
Que faire quand un CDN est devant
Un CDN change le diagnostic de deux façons utiles.
Les pages en cache continuent d'être servies. Un visiteur qui demande quelque chose déjà présent dans le cache de périphérie l'obtient même pendant que l'origine est en panne, donc un 502 partiel — certaines pages cassées, d'autres fonctionnelles — signifie généralement que l'origine est en ligne mais échoue sur les chemins non mis en cache, qui sont typiquement les chemins dynamiques.
Vous gagnez un second point de vue. La périphérie voit votre origine depuis l'extérieur, en continu. Si la périphérie signale un 502 et que votre propre navigateur atteint l'origine, la différence entre ces deux requêtes est le bug : un pare-feu qui autorise votre IP, un enregistrement DNS qui pointe ailleurs pour vous, ou un certificat qui ne correspond qu'au nom que vous utilisez par hasard.
Sur cdn.com.tr, les règles de diffusion vous permettent de garder un TTL de cache plus long sur les chemins qui peuvent le tolérer, ce qui transforme un incident d'origine en site dégradé plutôt qu'en site mort. Cela vaut la peine d'être configuré avant d'en avoir besoin, pas pendant.
Le 502 qui ne concerne pas du tout votre origine
Un cas mérite d'être nommé parce qu'il fait perdre des heures. Si votre DNS pointe vers une périphérie CDN mais que le nom d'hôte n'a pas encore été configuré sur cette périphérie, vous n'obtiendrez pas un 502 — vous obtiendrez un 503 avec une page disant qu'aucun service n'est configuré pour ce domaine. C'est la périphérie qui vous dit qu'elle n'a aucune idée de quelle origine interroger.
Les gens voient une page d'erreur juste après avoir changé le DNS, supposent que l'origine est cassée, et commencent à redémarrer des services qui n'ont jamais été concernés. Vérifiez d'abord le code de statut : 502 signifie que la périphérie a essayé votre origine et a échoué ; ce type de 503 signifie que la périphérie n'a jamais eu d'origine à essayer.
FAQ 502 Bad Gateway
Un 502 est-il de ma faute ou celle du CDN ?
Généralement ni l'un ni l'autre — c'est celle de l'origine. Le CDN rapporte l'échec qu'il a rencontré ; il ne l'invente pas. L'exception qui mérite d'être vérifiée est la connectivité : si le pare-feu de l'origine bloque les adresses IP de la périphérie, l'origine est saine pour vous et inaccessible pour le CDN, et la correction est une règle d'autorisation plutôt que quoi que ce soit sur l'application.
Pourquoi n'ai-je un 502 que parfois ?
Des 502 intermittents signifient presque toujours un problème de capacité plutôt que de configuration. Un pool de processus plein pendant les pics, un worker recyclé, ou une origine qui ferme les connexions keepalive plus tôt que ce que le proxy attend, vont tous produire des erreurs qui vont et viennent, alors qu'un simple test depuis votre ordinateur portable réussit à chaque fois.
Actualiser la page aide-t-il ?
Cela vous apprend quelque chose. Si une actualisation fonctionne, l'échec est intermittent et vous êtes face à un problème de capacité ou de worker spécifique. Si chaque actualisation échoue à l'identique, c'est une question de configuration — une connexion refusée, un mauvais port, un certificat d'origine expiré — et actualiser n'y changera rien.
Comment distinguer un 502 d'un 504 sans le code de statut ?
Par le temps que vous avez attendu. Un 504 vous fait attendre tout le délai, typiquement des dizaines de secondes, parce que le proxy attend réellement une réponse. Un 502 arrive généralement vite, car une connexion refusée ou rompue échoue rapidement.
Puis-je montrer à mes visiteurs quelque chose de mieux que la page d'erreur par défaut ?
Oui, et vous devriez le faire. Un CDN sert du contenu en cache légèrement périmé ou une page d'erreur personnalisée plutôt que la page par défaut du proxy, ce qui transforme une panne en une expérience un peu moins bonne que d'habitude plutôt qu'en expérience cassée. Configurez cela avant un incident, car pendant l'incident vous n'aurez pas l'attention à y consacrer.