[{"data":1,"prerenderedAt":714},["ShallowReactive",2],{"content-query-WD5oVqwB97":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"crumb":11,"summary":12,"group":13,"order":14,"code":14,"updated":15,"cta":16,"related":24,"faq":43,"body":59,"_type":707,"_id":708,"_source":709,"_file":710,"_stem":711,"_extension":712,"sitemap":713},"/http-errors/502-bad-gateway","http-errors",false,"","502 Bad Gateway: what it means and how to fix it","502 Bad Gateway means a proxy got no valid response from the server behind it. Causes and fixes for nginx, Cloudflare, AWS ALB, tunnels and webhook endpoints.","reference","502 Bad Gateway","A proxy couldn't get a valid response from the app behind it.","5xx server errors",502,"2026-10-28",{"eyebrow":17,"title":18,"text":19,"to":20,"label":21,"secondaryTo":22,"secondaryLabel":23},"Webhook Relay Durable Retries","Don't lose webhooks while your upstream is down","When your endpoint answers 502, most providers retry a few times and then drop the event. Webhook Relay stores every webhook first and retries with exponential backoff for up to 30 days, so a crashed app or bad deploy doesn't cost you data.","/features/durable-retries/","See durable retries","/docs/webhooks/durable-webhooks/","Durable webhooks docs",[25,28,31,34,37,40],{"title":26,"to":27},"504 Gateway Timeout","/http-errors/504-gateway-timeout/",{"title":29,"to":30},"503 Service Unavailable","/http-errors/503-service-unavailable/",{"title":32,"to":33},"500 Internal Server Error","/http-errors/500-internal-server-error/",{"title":35,"to":36},"Reverse proxy","/glossary/reverse-proxy/",{"title":38,"to":39},"localhost:3000","/localhost/3000/",{"title":41,"to":42},"Webhook retries","/glossary/webhook-retries/",[44,47,50,53,56],{"q":45,"a":46},"What does 502 Bad Gateway mean?","A 502 Bad Gateway means a server acting as a gateway or proxy, such as nginx, Cloudflare or a load balancer, tried to reach the server behind it and got an invalid response or none at all. The proxy is working; the application behind it is down, crashed, unreachable or sent back something the proxy couldn't use.",{"q":48,"a":49},"How do I fix 502 Bad Gateway in nginx?","Check the nginx error log first. Connection refused while connecting to upstream means the app isn't running or listens on a different port than proxy_pass. Upstream prematurely closed connection means the app crashed or was killed mid-request. Start or fix the app, make proxy_pass match its host and port, and reload nginx.",{"q":51,"a":52},"Is a 502 error my fault or the website's?","If you're visiting a site, it's almost always the website's problem. Reload after a minute, try another network, or check the site's status page. Clearing cookies or cache rarely helps, though it costs nothing to try.",{"q":54,"a":55},"Why does my tunnel or webhook forwarder return 502?","The tunnel reached your machine, but nothing answered on the local port it forwards to. The local app isn't running, crashed, listens on a different port, or expects plain HTTP while the tunnel is pointed at https. Start the app and check the port and scheme in the tunnel command.",{"q":57,"a":58},"Do webhook providers retry after a 502?","Most do, because 502 is a server error. But retry windows vary widely: some providers retry for days, some for minutes, and some never retry automatically. If the upstream stays down longer than the provider's window, the event is lost unless something in front of your endpoint stores it.",{"type":60,"children":61,"toc":699},"root",[62,82,149,156,227,233,238,244,249,437,442,532,544,550,570,610,616,621,656,662,693],{"type":63,"tag":64,"props":65,"children":66},"element","p",{},[67,80],{"type":63,"tag":68,"props":69,"children":70},"strong",{},[71,78],{"type":63,"tag":72,"props":73,"children":75},"code",{"className":74},[],[76],{"type":77,"value":11},"text",{"type":77,"value":79}," means a proxy or gateway (nginx, Cloudflare, a load balancer, a tunnel) tried to reach the server behind it and got an invalid response or no response at all.",{"type":77,"value":81}," The proxy itself is fine. The problem is the application it forwards to: it isn't running, it crashed mid-request, it's listening somewhere else, or it sent back something the proxy couldn't parse.",{"type":63,"tag":83,"props":84,"children":88},"pre",{"className":85,"code":86,"language":87,"meta":7,"style":7},"language-http shiki shiki-themes github-dark","HTTP/1.1 502 Bad Gateway\nServer: nginx\nContent-Type: text/html\n\n\u003Chtml>\u003Chead>\u003Ctitle>502 Bad Gateway\u003C/title>\u003C/head>\n\u003Cbody>\u003Ccenter>\u003Ch1>502 Bad Gateway\u003C/h1>\u003C/center>\u003Chr>\u003Ccenter>nginx\u003C/center>\u003C/body>\u003C/html>\n","http",[89],{"type":63,"tag":72,"props":90,"children":91},{"__ignoreMap":7},[92,103,112,121,131,140],{"type":63,"tag":93,"props":94,"children":97},"span",{"class":95,"line":96},"line",1,[98],{"type":63,"tag":93,"props":99,"children":100},{},[101],{"type":77,"value":102},"HTTP/1.1 502 Bad Gateway\n",{"type":63,"tag":93,"props":104,"children":106},{"class":95,"line":105},2,[107],{"type":63,"tag":93,"props":108,"children":109},{},[110],{"type":77,"value":111},"Server: nginx\n",{"type":63,"tag":93,"props":113,"children":115},{"class":95,"line":114},3,[116],{"type":63,"tag":93,"props":117,"children":118},{},[119],{"type":77,"value":120},"Content-Type: text/html\n",{"type":63,"tag":93,"props":122,"children":124},{"class":95,"line":123},4,[125],{"type":63,"tag":93,"props":126,"children":128},{"emptyLinePlaceholder":127},true,[129],{"type":77,"value":130},"\n",{"type":63,"tag":93,"props":132,"children":134},{"class":95,"line":133},5,[135],{"type":63,"tag":93,"props":136,"children":137},{},[138],{"type":77,"value":139},"\u003Chtml>\u003Chead>\u003Ctitle>502 Bad Gateway\u003C/title>\u003C/head>\n",{"type":63,"tag":93,"props":141,"children":143},{"class":95,"line":142},6,[144],{"type":63,"tag":93,"props":145,"children":146},{},[147],{"type":77,"value":148},"\u003Cbody>\u003Ccenter>\u003Ch1>502 Bad Gateway\u003C/h1>\u003C/center>\u003Chr>\u003Ccenter>nginx\u003C/center>\u003C/body>\u003C/html>\n",{"type":63,"tag":150,"props":151,"children":153},"h2",{"id":152},"common-causes",[154],{"type":77,"value":155},"Common causes",{"type":63,"tag":157,"props":158,"children":159},"ul",{},[160,171,197,207,217],{"type":63,"tag":161,"props":162,"children":163},"li",{},[164,169],{"type":63,"tag":68,"props":165,"children":166},{},[167],{"type":77,"value":168},"The upstream app isn't running.",{"type":77,"value":170}," The process crashed, failed to start after a deploy, or was killed by the OOM killer.",{"type":63,"tag":161,"props":172,"children":173},{},[174,179,181,187,189,195],{"type":63,"tag":68,"props":175,"children":176},{},[177],{"type":77,"value":178},"Wrong host or port.",{"type":77,"value":180}," ",{"type":63,"tag":72,"props":182,"children":184},{"className":183},[],[185],{"type":77,"value":186},"proxy_pass",{"type":77,"value":188},", the load balancer target or the tunnel points at a port nothing listens on, or the app binds to ",{"type":63,"tag":72,"props":190,"children":192},{"className":191},[],[193],{"type":77,"value":194},"127.0.0.1",{"type":77,"value":196}," inside a container so the proxy can't reach it.",{"type":63,"tag":161,"props":198,"children":199},{},[200,205],{"type":63,"tag":68,"props":201,"children":202},{},[203],{"type":77,"value":204},"The app closed the connection.",{"type":77,"value":206}," A worker was killed mid-request (Gunicorn's worker timeout is 30 seconds by default), or the app's keep-alive timeout is shorter than the proxy's, so the proxy reuses a connection the app already closed.",{"type":63,"tag":161,"props":208,"children":209},{},[210,215],{"type":63,"tag":68,"props":211,"children":212},{},[213],{"type":77,"value":214},"Scheme mismatch.",{"type":77,"value":216}," The proxy speaks HTTPS to an app serving plain HTTP, or the reverse.",{"type":63,"tag":161,"props":218,"children":219},{},[220,225],{"type":63,"tag":68,"props":221,"children":222},{},[223],{"type":77,"value":224},"Invalid response.",{"type":77,"value":226}," Oversized headers, a malformed status line, or a broken TLS handshake between proxy and origin.",{"type":63,"tag":150,"props":228,"children":230},{"id":229},"how-to-fix-it-as-a-visitor",[231],{"type":77,"value":232},"How to fix it as a visitor",{"type":63,"tag":64,"props":234,"children":235},{},[236],{"type":77,"value":237},"Reload after a minute. A 502 is often a short window during a deploy or restart. If it persists, try another network or check the site's status page. It's a server-side problem, so there's little else you can do.",{"type":63,"tag":150,"props":239,"children":241},{"id":240},"how-to-fix-it-as-a-developer-or-ops",[242],{"type":77,"value":243},"How to fix it as a developer or ops",{"type":63,"tag":64,"props":245,"children":246},{},[247],{"type":77,"value":248},"Start with the proxy's error log. It almost always names the cause.",{"type":63,"tag":250,"props":251,"children":252},"table",{},[253,277],{"type":63,"tag":254,"props":255,"children":256},"thead",{},[257],{"type":63,"tag":258,"props":259,"children":260},"tr",{},[261,267,272],{"type":63,"tag":262,"props":263,"children":264},"th",{},[265],{"type":77,"value":266},"Where",{"type":63,"tag":262,"props":268,"children":269},{},[270],{"type":77,"value":271},"What you see",{"type":63,"tag":262,"props":273,"children":274},{},[275],{"type":77,"value":276},"What it means",{"type":63,"tag":278,"props":279,"children":280},"tbody",{},[281,311,332,361,405],{"type":63,"tag":258,"props":282,"children":283},{},[284,290,299],{"type":63,"tag":285,"props":286,"children":287},"td",{},[288],{"type":77,"value":289},"nginx",{"type":63,"tag":285,"props":291,"children":292},{},[293],{"type":63,"tag":72,"props":294,"children":296},{"className":295},[],[297],{"type":77,"value":298},"connect() failed (111: Connection refused) while connecting to upstream",{"type":63,"tag":285,"props":300,"children":301},{},[302,304,309],{"type":77,"value":303},"Nothing listens at the ",{"type":63,"tag":72,"props":305,"children":307},{"className":306},[],[308],{"type":77,"value":186},{"type":77,"value":310}," address. Start the app or fix the port.",{"type":63,"tag":258,"props":312,"children":313},{},[314,318,327],{"type":63,"tag":285,"props":315,"children":316},{},[317],{"type":77,"value":289},{"type":63,"tag":285,"props":319,"children":320},{},[321],{"type":63,"tag":72,"props":322,"children":324},{"className":323},[],[325],{"type":77,"value":326},"upstream prematurely closed connection while reading response header",{"type":63,"tag":285,"props":328,"children":329},{},[330],{"type":77,"value":331},"The app crashed or was killed mid-request. Check app logs and worker timeouts.",{"type":63,"tag":258,"props":333,"children":334},{},[335,339,348],{"type":63,"tag":285,"props":336,"children":337},{},[338],{"type":77,"value":289},{"type":63,"tag":285,"props":340,"children":341},{},[342],{"type":63,"tag":72,"props":343,"children":345},{"className":344},[],[346],{"type":77,"value":347},"no live upstreams while connecting to upstream",{"type":63,"tag":285,"props":349,"children":350},{},[351,353,359],{"type":77,"value":352},"Every server in the ",{"type":63,"tag":72,"props":354,"children":356},{"className":355},[],[357],{"type":77,"value":358},"upstream",{"type":77,"value":360}," block is marked failed.",{"type":63,"tag":258,"props":362,"children":363},{},[364,369,393],{"type":63,"tag":285,"props":365,"children":366},{},[367],{"type":77,"value":368},"Cloudflare",{"type":63,"tag":285,"props":370,"children":371},{},[372,377,379,385,387],{"type":63,"tag":72,"props":373,"children":375},{"className":374},[],[376],{"type":77,"value":11},{"type":77,"value":378}," or ",{"type":63,"tag":72,"props":380,"children":382},{"className":381},[],[383],{"type":77,"value":384},"Error 520",{"type":77,"value":386},"/",{"type":63,"tag":72,"props":388,"children":390},{"className":389},[],[391],{"type":77,"value":392},"521",{"type":63,"tag":285,"props":394,"children":395},{},[396,398,403],{"type":77,"value":397},"The origin refused, reset or returned an invalid response. ",{"type":63,"tag":72,"props":399,"children":401},{"className":400},[],[402],{"type":77,"value":392},{"type":77,"value":404}," means it refused the connection.",{"type":63,"tag":258,"props":406,"children":407},{},[408,413,432],{"type":63,"tag":285,"props":409,"children":410},{},[411],{"type":77,"value":412},"AWS ALB",{"type":63,"tag":285,"props":414,"children":415},{},[416,422,424,430],{"type":63,"tag":72,"props":417,"children":419},{"className":418},[],[420],{"type":77,"value":421},"502",{"type":77,"value":423}," in access logs, with ",{"type":63,"tag":72,"props":425,"children":427},{"className":426},[],[428],{"type":77,"value":429},"target_status_code",{"type":77,"value":431}," logged as a dash (no response)",{"type":63,"tag":285,"props":433,"children":434},{},[435],{"type":77,"value":436},"The target closed the connection or sent a malformed response.",{"type":63,"tag":64,"props":438,"children":439},{},[440],{"type":77,"value":441},"Specific fixes:",{"type":63,"tag":443,"props":444,"children":445},"ol",{},[446,464,489,507],{"type":63,"tag":161,"props":447,"children":448},{},[449,454,456,462],{"type":63,"tag":68,"props":450,"children":451},{},[452],{"type":77,"value":453},"Confirm the app answers locally",{"type":77,"value":455},": ",{"type":63,"tag":72,"props":457,"children":459},{"className":458},[],[460],{"type":77,"value":461},"curl -v http://127.0.0.1:8000/",{"type":77,"value":463}," from the proxy host. If that fails, the problem isn't the proxy.",{"type":63,"tag":161,"props":465,"children":466},{},[467,472,474,480,482,487],{"type":63,"tag":68,"props":468,"children":469},{},[470],{"type":77,"value":471},"Bind to the right interface.",{"type":77,"value":473}," In Docker, the app must listen on ",{"type":63,"tag":72,"props":475,"children":477},{"className":476},[],[478],{"type":77,"value":479},"0.0.0.0",{"type":77,"value":481},", not ",{"type":63,"tag":72,"props":483,"children":485},{"className":484},[],[486],{"type":77,"value":194},{"type":77,"value":488},", for another container to reach it.",{"type":63,"tag":161,"props":490,"children":491},{},[492,497,499,505],{"type":63,"tag":68,"props":493,"children":494},{},[495],{"type":77,"value":496},"Line up keep-alive timeouts.",{"type":77,"value":498}," Behind an AWS ALB (idle timeout 60 seconds by default), set the app's keep-alive timeout higher than the ALB's. Node.js defaults ",{"type":63,"tag":72,"props":500,"children":502},{"className":501},[],[503],{"type":77,"value":504},"server.keepAliveTimeout",{"type":77,"value":506}," to 5 seconds, a classic cause of intermittent ALB 502s.",{"type":63,"tag":161,"props":508,"children":509},{},[510,515,516,522,524,530],{"type":63,"tag":68,"props":511,"children":512},{},[513],{"type":77,"value":514},"Check memory and restarts.",{"type":77,"value":180},{"type":63,"tag":72,"props":517,"children":519},{"className":518},[],[520],{"type":77,"value":521},"dmesg | grep -i oom",{"type":77,"value":523},", ",{"type":63,"tag":72,"props":525,"children":527},{"className":526},[],[528],{"type":77,"value":529},"kubectl describe pod",{"type":77,"value":531},", or your process manager's logs show whether the app keeps dying.",{"type":63,"tag":64,"props":533,"children":534},{},[535,537,542],{"type":77,"value":536},"If the proxy waited for the app and gave up instead, that's a ",{"type":63,"tag":538,"props":539,"children":540},"a",{"href":27},[541],{"type":77,"value":26},{"type":77,"value":543},", not a 502.",{"type":63,"tag":150,"props":545,"children":547},{"id":546},"_502-from-a-tunnel-or-local-webhook-forwarder",[548],{"type":77,"value":549},"502 from a tunnel or local webhook forwarder",{"type":63,"tag":64,"props":551,"children":552},{},[553,555,561,562,568],{"type":77,"value":554},"A 502 is the classic tunnel error. The tunnel reached your machine, but the local app it forwards to didn't answer. With ",{"type":63,"tag":72,"props":556,"children":558},{"className":557},[],[559],{"type":77,"value":560},"relay connect --name my-app http://localhost:3000",{"type":77,"value":378},{"type":63,"tag":72,"props":563,"children":565},{"className":564},[],[566],{"type":77,"value":567},"relay forward --bucket my-app http://localhost:3000/webhooks",{"type":77,"value":569},", a 502 or a timeout reported by the provider means the agent couldn't reach the destination. Check that:",{"type":63,"tag":157,"props":571,"children":572},{},[573,584,589],{"type":63,"tag":161,"props":574,"children":575},{},[576,578,582],{"type":77,"value":577},"the dev server is actually running and listening on that port (see ",{"type":63,"tag":538,"props":579,"children":580},{"href":39},[581],{"type":77,"value":38},{"type":77,"value":583}," for \"refused to connect\" fixes);",{"type":63,"tag":161,"props":585,"children":586},{},[587],{"type":77,"value":588},"the port in the command matches the one your app printed on startup;",{"type":63,"tag":161,"props":590,"children":591},{},[592,594,600,602,608],{"type":77,"value":593},"you used ",{"type":63,"tag":72,"props":595,"children":597},{"className":596},[],[598],{"type":77,"value":599},"http://",{"type":77,"value":601}," for a plain local server, not ",{"type":63,"tag":72,"props":603,"children":605},{"className":604},[],[606],{"type":77,"value":607},"https://",{"type":77,"value":609},".",{"type":63,"tag":150,"props":611,"children":613},{"id":612},"_502s-on-a-webhook-endpoint",[614],{"type":77,"value":615},"502s on a webhook endpoint",{"type":63,"tag":64,"props":617,"children":618},{},[619],{"type":77,"value":620},"When a provider gets a 502 from your webhook endpoint, it counts as a failed delivery. Most providers retry, but their windows vary from days to minutes, and some never retry automatically. A bad deploy that leaves the app down for an hour can silently lose events.",{"type":63,"tag":64,"props":622,"children":623},{},[624,626,631,633,639,641,647,649,655],{"type":77,"value":625},"The fix is to make sure the event is stored somewhere before your app has to be up. Webhook Relay ",{"type":63,"tag":538,"props":627,"children":628},{"href":20},[629],{"type":77,"value":630},"durable retries",{"type":77,"value":632}," persist each webhook first, then retry with ",{"type":63,"tag":538,"props":634,"children":636},{"href":635},"/glossary/exponential-backoff/",[637],{"type":77,"value":638},"exponential backoff",{"type":77,"value":640}," for up to 30 days until your endpoint returns ",{"type":63,"tag":72,"props":642,"children":644},{"className":643},[],[645],{"type":77,"value":646},"2xx",{"type":77,"value":648},". Because delivery is at least once, make your handler ",{"type":63,"tag":538,"props":650,"children":652},{"href":651},"/glossary/idempotency/",[653],{"type":77,"value":654},"idempotent",{"type":77,"value":609},{"type":63,"tag":150,"props":657,"children":659},{"id":658},"when-to-return-502-from-your-own-service",[660],{"type":77,"value":661},"When to return 502 from your own service",{"type":63,"tag":64,"props":663,"children":664},{},[665,667,672,674,682,684,692],{"type":77,"value":666},"Return ",{"type":63,"tag":72,"props":668,"children":670},{"className":669},[],[671],{"type":77,"value":421},{"type":77,"value":673}," only when your service is itself acting as a gateway and the upstream it called returned something invalid. If your own code failed, that's a ",{"type":63,"tag":538,"props":675,"children":676},{"href":33},[677],{"type":63,"tag":72,"props":678,"children":680},{"className":679},[],[681],{"type":77,"value":32},{"type":77,"value":683},". If you're deliberately refusing traffic during maintenance or overload, use ",{"type":63,"tag":538,"props":685,"children":686},{"href":30},[687],{"type":63,"tag":72,"props":688,"children":690},{"className":689},[],[691],{"type":77,"value":29},{"type":77,"value":609},{"type":63,"tag":694,"props":695,"children":696},"style",{},[697],{"type":77,"value":698},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":114,"depth":114,"links":700},[701,702,703,704,705,706],{"id":152,"depth":105,"text":155},{"id":229,"depth":105,"text":232},{"id":240,"depth":105,"text":243},{"id":546,"depth":105,"text":549},{"id":612,"depth":105,"text":615},{"id":658,"depth":105,"text":661},"markdown","content:http-errors:502-bad-gateway.md","content","http-errors/502-bad-gateway.md","http-errors/502-bad-gateway","md",{"loc":4},1793199802747]