Reverse Proxies Explained
Trace requests through a reverse proxy and understand the separate decisions around upstreams, headers, streaming, and failures.
One public endpoint can serve several applications
A reverse proxy accepts a client's request and forwards it to an upstream service according to its configuration. The upstream might be a process on the same machine, a private-network application, or another explicitly configured endpoint. The client-facing server and the application server become separate operational components.
This creates useful boundaries. The public endpoint can manage TLS, route by hostname or path, and provide common logging while an application listens on a private address. Each boundary also introduces a place where configuration can disagree with the application's expectations.
Draw the request path before deploying it. A concise diagram such as “browser → proxy → application” should identify the address, port, and encryption policy of each hop. That is more actionable than merely naming the proxy software.
A minimal configuration is a starting point
This illustrative Caddyfile routes a documentation hostname to a local application. It assumes that the application is actually listening on the selected loopback port and that the hostname is appropriately configured.
app.example.com {
reverse_proxy 127.0.0.1:8080
}
The Caddy reverse_proxy reference describes upstream transports, request headers, streaming behavior, and health checks. A short configuration can rely on sensible defaults, but it should not be mistaken for a complete description of every application's requirements.
First test the upstream locally, then test the public hostname. This separates an application that never started from a proxy that cannot route to it. Store the working configuration and the validation procedure together so that a later edit has a known baseline.
Preserve the application's view of the request
An upstream may need to know the original scheme, host, and client address. Proxies can communicate that context through forwarded fields. However, clients can also submit fields with similar names, so accepting them blindly can turn untrusted input into apparently authoritative metadata.
RFC 7239 defines the Forwarded field and explains relevant security and privacy considerations. Existing deployments also commonly use X-Forwarded-* conventions, whose interpretation must match the proxy and application configuration.
Trust should follow topology. An application reachable only through one controlled proxy can use a narrowly defined trusted-proxy policy. An application exposed directly as well as through the proxy has a different risk. Test redirects and absolute URLs because incorrect scheme information can surface as redirect loops or links pointing to the wrong origin.
Buffering changes streaming behavior
NGINX provides explicit proxy buffering controls. With response buffering enabled, it reads data from the upstream into configured buffers and may use temporary files; when disabled, it passes data to the client as it receives it, subject to transport behavior. Request buffering is a separate control. The details are in the NGINX proxy module documentation.
No single buffering choice fits every workload. A small JSON response, a large downloadable object, and an event stream place different demands on latency, memory, disk activity, and slow-client handling.
For a media application, validate playback and seeking with representative files rather than copying a generic “streaming configuration.” Measure both proxy legs and inspect resource use. A fast upstream cannot compensate for a slow client-facing connection, and disabling buffering cannot create missing bandwidth.
HTTP details still matter
Range requests allow a client to ask for selected portions of a representation. Conditional requests and caching fields help determine whether a response can be reused. These semantics are specified in RFC 9110.
A proxy configuration should preserve the behavior the application requires. For a seek operation, inspect the request's range, the response status, and the relevant response fields. A successful home page says little about whether a large media object supports the intended access pattern.
Keep diagnostic claims narrow. A 502 response indicates a gateway-related failure, while a 504 indicates a gateway timeout condition; neither status alone identifies the exact root cause. Application logs and proxy logs are complementary evidence, especially when a request crosses several components.
Distinguish the two transport connections
A client-to-proxy connection and a proxy-to-upstream connection can have different protocols, congestion behavior, latency, and lifetime. TLS can end at the proxy and begin again on the upstream hop, or the upstream can be local cleartext where that is a deliberate design choice.
Consider an illustrative video request needing 20 megabits per second. A 100 megabit upstream path and a client-facing path that sustains only 12 megabits will not deliver that request at its required rate. Reversing those capacities changes the constrained hop but not the need to examine both.
Parallel benchmarks provide aggregate evidence. A single media request can still be limited by one flow, so record the single-connection result and sustained intervals when assessing playback headroom.
Validate behavior and keep a rollback
Before loading a changed proxy configuration, validate its syntax and retain the previous working version. After loading it, check a small set of representative operations: the main page, an authenticated request, a redirect, a large response, and any streaming or upgrade behavior the application uses.
Use a request identifier or timestamps to connect client observations with proxy and upstream logs. Redact tokens, cookies, and private addresses when sharing traces externally. A log that exposes credentials creates a new problem while trying to explain the old one.
The final operational record should state what the proxy routes, which upstream it trusts, how it verifies any upstream TLS, and how to revert a change. Those details make the endpoint maintainable long after the initial configuration succeeds.