[{"data":1,"prerenderedAt":652},["ShallowReactive",2],{"content-query-CDEyioiewj":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"crumb":11,"term":11,"summary":12,"group":13,"order":14,"updated":15,"cta":16,"related":24,"faq":43,"body":56,"_type":645,"_id":646,"_source":647,"_file":648,"_stem":649,"_extension":650,"sitemap":651},"/glossary/reverse-proxy","glossary",false,"","What is a reverse proxy? Definition and nginx example","A reverse proxy is a server that sits in front of your app, receives client requests and forwards them to it. How it works, an nginx config, and the 502 and 504 errors it causes.","reference","Reverse proxy","A server in front of your app that receives requests and passes them on.","Infrastructure",33,"2026-10-28",{"eyebrow":17,"title":18,"text":19,"to":20,"label":21,"secondaryTo":22,"secondaryLabel":23},"Webhook Relay","A reverse proxy that reaches servers with no public IP","Webhook Relay tunnels act as a hosted reverse proxy for localhost and private networks: a public HTTPS URL forwards to your server over an outbound connection. For webhooks, forwarding adds storage and retries, so a down upstream doesn't lose events.","/tunnels/","See tunnels","/webhook-gateway/","Webhook forwarding",[25,28,31,34,37,40],{"title":26,"to":27},"502 Bad Gateway","/http-errors/502-bad-gateway/",{"title":29,"to":30},"504 Gateway Timeout","/http-errors/504-gateway-timeout/",{"title":32,"to":33},"413 Payload Too Large","/http-errors/413-payload-too-large/",{"title":35,"to":36},"Tunnel","/glossary/tunnel/",{"title":38,"to":39},"Webhook gateway","/glossary/webhook-gateway/",{"title":41,"to":42},"Rewrite Host header","/features/rewrite-host-header/",[44,47,50,53],{"q":45,"a":46},"What is a reverse proxy?","A reverse proxy is a server that sits in front of one or more backend servers, receives requests from clients and forwards them to the right backend, then returns the backend's response to the client. Clients only talk to the proxy. Common reverse proxies are nginx, Caddy, HAProxy, Traefik, Envoy and cloud load balancers.",{"q":48,"a":49},"What is the difference between a forward proxy and a reverse proxy?","A forward proxy acts for clients: it sits in front of users and makes requests to the internet on their behalf, for filtering or privacy. A reverse proxy acts for servers: it sits in front of your application and receives requests from the internet on its behalf.",{"q":51,"a":52},"Why does my reverse proxy return 502 Bad Gateway?","The proxy reached out to the backend and got no valid response: the app isn't running, it's listening on a different port or interface, it crashed mid-request, or the proxy can't resolve or connect to the upstream address. Check that the upstream address in the proxy config matches where the app actually listens.",{"q":54,"a":55},"Why does my reverse proxy return 504 Gateway Timeout?","The backend accepted the connection but didn't respond within the proxy's timeout, which is 60 seconds by default for nginx's proxy_read_timeout. Speed up the handler, move slow work to a background job, or raise the timeout if long responses are expected.",{"type":57,"children":58,"toc":638},"root",[59,73,204,211,260,266,368,374,379,472,478,483,583,589,632],{"type":60,"tag":61,"props":62,"children":63},"element","p",{},[64,71],{"type":60,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":69,"value":70},"text","A reverse proxy is a server that sits in front of your application, receives requests from clients and forwards them to the app, then sends the app's response back.",{"type":69,"value":72}," Clients only ever talk to the proxy. It's where TLS is terminated, requests are routed to the right backend, and traffic is load-balanced, cached, compressed or rate-limited. nginx, Caddy, HAProxy, Traefik, Envoy and cloud load balancers are all reverse proxies.",{"type":60,"tag":74,"props":75,"children":79},"pre",{"className":76,"code":77,"language":78,"meta":7,"style":7},"language-nginx shiki shiki-themes github-dark","server {\n    listen 443 ssl;\n    server_name api.example.com;\n\n    location /webhooks/ {\n        proxy_pass http://127.0.0.1:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_read_timeout 30s;\n        client_max_body_size 10m;\n    }\n}\n","nginx",[80],{"type":60,"tag":81,"props":82,"children":83},"code",{"__ignoreMap":7},[84,95,104,113,123,132,141,150,159,168,177,186,195],{"type":60,"tag":85,"props":86,"children":89},"span",{"class":87,"line":88},"line",1,[90],{"type":60,"tag":85,"props":91,"children":92},{},[93],{"type":69,"value":94},"server {\n",{"type":60,"tag":85,"props":96,"children":98},{"class":87,"line":97},2,[99],{"type":60,"tag":85,"props":100,"children":101},{},[102],{"type":69,"value":103},"    listen 443 ssl;\n",{"type":60,"tag":85,"props":105,"children":107},{"class":87,"line":106},3,[108],{"type":60,"tag":85,"props":109,"children":110},{},[111],{"type":69,"value":112},"    server_name api.example.com;\n",{"type":60,"tag":85,"props":114,"children":116},{"class":87,"line":115},4,[117],{"type":60,"tag":85,"props":118,"children":120},{"emptyLinePlaceholder":119},true,[121],{"type":69,"value":122},"\n",{"type":60,"tag":85,"props":124,"children":126},{"class":87,"line":125},5,[127],{"type":60,"tag":85,"props":128,"children":129},{},[130],{"type":69,"value":131},"    location /webhooks/ {\n",{"type":60,"tag":85,"props":133,"children":135},{"class":87,"line":134},6,[136],{"type":60,"tag":85,"props":137,"children":138},{},[139],{"type":69,"value":140},"        proxy_pass http://127.0.0.1:3000;\n",{"type":60,"tag":85,"props":142,"children":144},{"class":87,"line":143},7,[145],{"type":60,"tag":85,"props":146,"children":147},{},[148],{"type":69,"value":149},"        proxy_set_header Host $host;\n",{"type":60,"tag":85,"props":151,"children":153},{"class":87,"line":152},8,[154],{"type":60,"tag":85,"props":155,"children":156},{},[157],{"type":69,"value":158},"        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",{"type":60,"tag":85,"props":160,"children":162},{"class":87,"line":161},9,[163],{"type":60,"tag":85,"props":164,"children":165},{},[166],{"type":69,"value":167},"        proxy_set_header X-Forwarded-Proto $scheme;\n",{"type":60,"tag":85,"props":169,"children":171},{"class":87,"line":170},10,[172],{"type":60,"tag":85,"props":173,"children":174},{},[175],{"type":69,"value":176},"        proxy_read_timeout 30s;\n",{"type":60,"tag":85,"props":178,"children":180},{"class":87,"line":179},11,[181],{"type":60,"tag":85,"props":182,"children":183},{},[184],{"type":69,"value":185},"        client_max_body_size 10m;\n",{"type":60,"tag":85,"props":187,"children":189},{"class":87,"line":188},12,[190],{"type":60,"tag":85,"props":191,"children":192},{},[193],{"type":69,"value":194},"    }\n",{"type":60,"tag":85,"props":196,"children":198},{"class":87,"line":197},13,[199],{"type":60,"tag":85,"props":200,"children":201},{},[202],{"type":69,"value":203},"}\n",{"type":60,"tag":205,"props":206,"children":208},"h2",{"id":207},"how-a-reverse-proxy-works",[209],{"type":69,"value":210},"How a reverse proxy works",{"type":60,"tag":212,"props":213,"children":214},"ol",{},[215,229,234,255],{"type":60,"tag":216,"props":217,"children":218},"li",{},[219,221,227],{"type":69,"value":220},"A client resolves ",{"type":60,"tag":81,"props":222,"children":224},{"className":223},[],[225],{"type":69,"value":226},"api.example.com",{"type":69,"value":228}," to the proxy's IP and opens an HTTPS connection to it.",{"type":60,"tag":216,"props":230,"children":231},{},[232],{"type":69,"value":233},"The proxy terminates TLS, reads the request and picks an upstream based on host, path or load-balancing rules.",{"type":60,"tag":216,"props":235,"children":236},{},[237,239,245,247,253],{"type":69,"value":238},"It opens a connection to the upstream, for example ",{"type":60,"tag":81,"props":240,"children":242},{"className":241},[],[243],{"type":69,"value":244},"127.0.0.1:3000",{"type":69,"value":246},", and forwards the request, adding headers such as ",{"type":60,"tag":81,"props":248,"children":250},{"className":249},[],[251],{"type":69,"value":252},"X-Forwarded-For",{"type":69,"value":254}," so the app knows the original client.",{"type":60,"tag":216,"props":256,"children":257},{},[258],{"type":69,"value":259},"It relays the upstream's response to the client, or generates an error if the upstream fails.",{"type":60,"tag":205,"props":261,"children":263},{"id":262},"forward-proxy-vs-reverse-proxy",[264],{"type":69,"value":265},"Forward proxy vs reverse proxy",{"type":60,"tag":267,"props":268,"children":269},"table",{},[270,291],{"type":60,"tag":271,"props":272,"children":273},"thead",{},[274],{"type":60,"tag":275,"props":276,"children":277},"tr",{},[278,282,287],{"type":60,"tag":279,"props":280,"children":281},"th",{},[],{"type":60,"tag":279,"props":283,"children":284},{},[285],{"type":69,"value":286},"Forward proxy",{"type":60,"tag":279,"props":288,"children":289},{},[290],{"type":69,"value":11},{"type":60,"tag":292,"props":293,"children":294},"tbody",{},[295,314,332,350],{"type":60,"tag":275,"props":296,"children":297},{},[298,304,309],{"type":60,"tag":299,"props":300,"children":301},"td",{},[302],{"type":69,"value":303},"Acts on behalf of",{"type":60,"tag":299,"props":305,"children":306},{},[307],{"type":69,"value":308},"Clients",{"type":60,"tag":299,"props":310,"children":311},{},[312],{"type":69,"value":313},"Servers",{"type":60,"tag":275,"props":315,"children":316},{},[317,322,327],{"type":60,"tag":299,"props":318,"children":319},{},[320],{"type":69,"value":321},"Sits in front of",{"type":60,"tag":299,"props":323,"children":324},{},[325],{"type":69,"value":326},"Users' devices",{"type":60,"tag":299,"props":328,"children":329},{},[330],{"type":69,"value":331},"Your application",{"type":60,"tag":275,"props":333,"children":334},{},[335,340,345],{"type":60,"tag":299,"props":336,"children":337},{},[338],{"type":69,"value":339},"Typical use",{"type":60,"tag":299,"props":341,"children":342},{},[343],{"type":69,"value":344},"Filtering, privacy, egress control",{"type":60,"tag":299,"props":346,"children":347},{},[348],{"type":69,"value":349},"TLS, routing, load balancing, caching",{"type":60,"tag":275,"props":351,"children":352},{},[353,358,363],{"type":60,"tag":299,"props":354,"children":355},{},[356],{"type":69,"value":357},"Who configures it",{"type":60,"tag":299,"props":359,"children":360},{},[361],{"type":69,"value":362},"The client side",{"type":60,"tag":299,"props":364,"children":365},{},[366],{"type":69,"value":367},"The server side",{"type":60,"tag":205,"props":369,"children":371},{"id":370},"errors-a-reverse-proxy-generates",[372],{"type":69,"value":373},"Errors a reverse proxy generates",{"type":60,"tag":61,"props":375,"children":376},{},[377],{"type":69,"value":378},"When something goes wrong behind the proxy, the error comes from the proxy, not your app:",{"type":60,"tag":380,"props":381,"children":382},"ul",{},[383,396,416,430,450],{"type":60,"tag":216,"props":384,"children":385},{},[386,394],{"type":60,"tag":65,"props":387,"children":388},{},[389],{"type":60,"tag":390,"props":391,"children":392},"a",{"href":27},[393],{"type":69,"value":26},{"type":69,"value":395},": the proxy couldn't get a valid response. The app is down, listening on another port, bound to the wrong interface, or crashed mid-request.",{"type":60,"tag":216,"props":397,"children":398},{},[399,406,408,414],{"type":60,"tag":65,"props":400,"children":401},{},[402],{"type":60,"tag":390,"props":403,"children":404},{"href":30},[405],{"type":69,"value":29},{"type":69,"value":407},": the app accepted the connection but didn't answer within the proxy's timeout (",{"type":60,"tag":81,"props":409,"children":411},{"className":410},[],[412],{"type":69,"value":413},"proxy_read_timeout",{"type":69,"value":415}," defaults to 60 seconds in nginx).",{"type":60,"tag":216,"props":417,"children":418},{},[419,428],{"type":60,"tag":65,"props":420,"children":421},{},[422],{"type":60,"tag":390,"props":423,"children":425},{"href":424},"/http-errors/503-service-unavailable/",[426],{"type":69,"value":427},"503 Service Unavailable",{"type":69,"value":429},": no healthy upstreams, or the proxy is shedding load.",{"type":60,"tag":216,"props":431,"children":432},{},[433,440,442,448],{"type":60,"tag":65,"props":434,"children":435},{},[436],{"type":60,"tag":390,"props":437,"children":438},{"href":33},[439],{"type":69,"value":32},{"type":69,"value":441},": the body is over ",{"type":60,"tag":81,"props":443,"children":445},{"className":444},[],[446],{"type":69,"value":447},"client_max_body_size",{"type":69,"value":449}," (1 MB by default in nginx).",{"type":60,"tag":216,"props":451,"children":452},{},[453,462,464,470],{"type":60,"tag":65,"props":454,"children":455},{},[456],{"type":60,"tag":390,"props":457,"children":459},{"href":458},"/http-errors/429-too-many-requests/",[460],{"type":69,"value":461},"429 Too Many Requests",{"type":69,"value":463},": a rate limit such as nginx ",{"type":60,"tag":81,"props":465,"children":467},{"className":466},[],[468],{"type":69,"value":469},"limit_req",{"type":69,"value":471}," fired.",{"type":60,"tag":205,"props":473,"children":475},{"id":474},"reverse-proxies-and-webhooks",[476],{"type":69,"value":477},"Reverse proxies and webhooks",{"type":60,"tag":61,"props":479,"children":480},{},[481],{"type":69,"value":482},"Most webhook endpoints sit behind a reverse proxy, and a few settings matter:",{"type":60,"tag":380,"props":484,"children":485},{},[486,504,514,532,566],{"type":60,"tag":216,"props":487,"children":488},{},[489,494,496,502],{"type":60,"tag":65,"props":490,"children":491},{},[492],{"type":69,"value":493},"Timeouts.",{"type":69,"value":495}," Providers time out in seconds. If your proxy waits 60 seconds for a slow handler, the provider has already given up and will ",{"type":60,"tag":390,"props":497,"children":499},{"href":498},"/glossary/webhook-retries/",[500],{"type":69,"value":501},"retry",{"type":69,"value":503},". Keep handlers fast.",{"type":60,"tag":216,"props":505,"children":506},{},[507,512],{"type":60,"tag":65,"props":508,"children":509},{},[510],{"type":69,"value":511},"Body size.",{"type":69,"value":513}," Large payloads, such as GitHub push events with many commits, can exceed the default 1 MB body limit.",{"type":60,"tag":216,"props":515,"children":516},{},[517,522,524,530],{"type":60,"tag":65,"props":518,"children":519},{},[520],{"type":69,"value":521},"Don't modify the body.",{"type":69,"value":523}," Compression, buffering rewrites or body-inspecting middleware that changes bytes will break ",{"type":60,"tag":390,"props":525,"children":527},{"href":526},"/glossary/webhook-signature/",[528],{"type":69,"value":529},"signature verification",{"type":69,"value":531},".",{"type":60,"tag":216,"props":533,"children":534},{},[535,540,542,548,550,556,558,564],{"type":60,"tag":65,"props":536,"children":537},{},[538],{"type":69,"value":539},"Preserve headers.",{"type":69,"value":541}," Signature headers like ",{"type":60,"tag":81,"props":543,"children":545},{"className":544},[],[546],{"type":69,"value":547},"Stripe-Signature",{"type":69,"value":549}," or ",{"type":60,"tag":81,"props":551,"children":553},{"className":552},[],[554],{"type":69,"value":555},"webhook-signature",{"type":69,"value":557}," must reach the app. Some proxies drop headers with underscores (nginx does unless ",{"type":60,"tag":81,"props":559,"children":561},{"className":560},[],[562],{"type":69,"value":563},"underscores_in_headers on",{"type":69,"value":565},").",{"type":60,"tag":216,"props":567,"children":568},{},[569,574,576,581],{"type":60,"tag":65,"props":570,"children":571},{},[572],{"type":69,"value":573},"The proxy doesn't store requests.",{"type":69,"value":575}," If the app is down, the provider gets a 502 and you depend entirely on its retry policy. A ",{"type":60,"tag":390,"props":577,"children":578},{"href":39},[579],{"type":69,"value":580},"webhook gateway",{"type":69,"value":582}," is the store-and-retry alternative.",{"type":60,"tag":205,"props":584,"children":586},{"id":585},"reverse-proxies-for-localhost-and-private-networks",[587],{"type":69,"value":588},"Reverse proxies for localhost and private networks",{"type":60,"tag":61,"props":590,"children":591},{},[592,594,599,601,607,609,614,616,622,624,630],{"type":69,"value":593},"A classic reverse proxy needs a public IP and an open port. When the backend is on a laptop or behind a firewall, a ",{"type":60,"tag":390,"props":595,"children":596},{"href":36},[597],{"type":69,"value":598},"tunnel",{"type":69,"value":600}," does the same job from the outside: a hosted reverse proxy on the internet, connected to your machine by an outbound connection the agent opens. With Webhook Relay, ",{"type":60,"tag":81,"props":602,"children":604},{"className":603},[],[605],{"type":69,"value":606},"relay connect --name my-app http://localhost:3000",{"type":69,"value":608}," gives your local server a public HTTPS URL, and the ",{"type":60,"tag":390,"props":610,"children":611},{"href":42},[612],{"type":69,"value":613},"Host header can be rewritten",{"type":69,"value":615}," for apps that check it. For webhooks, ",{"type":60,"tag":390,"props":617,"children":619},{"href":618},"/glossary/webhook-forwarding/",[620],{"type":69,"value":621},"webhook forwarding",{"type":69,"value":623}," adds storage, ",{"type":60,"tag":390,"props":625,"children":627},{"href":626},"/features/durable-retries/",[628],{"type":69,"value":629},"durable retries",{"type":69,"value":631}," and fan-out on top.",{"type":60,"tag":633,"props":634,"children":635},"style",{},[636],{"type":69,"value":637},"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":106,"depth":106,"links":639},[640,641,642,643,644],{"id":207,"depth":97,"text":210},{"id":262,"depth":97,"text":265},{"id":370,"depth":97,"text":373},{"id":474,"depth":97,"text":477},{"id":585,"depth":97,"text":588},"markdown","content:glossary:reverse-proxy.md","content","glossary/reverse-proxy.md","glossary/reverse-proxy","md",{"loc":4},1793199807764]