Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To find which proxy returned a 502 or 504, compare the access logs for the same request at every NGINX hop. At each hop, record its client-facing $status beside $upstream_addr, $upstream_status, upstream timings, and a request ID if your configuration already propagates one. The proxy whose own $status is 502 or 504 sent that response to its downstream client; the browser’s status alone cannot identify which layer generated it.

Log the response and upstream attempt at every NGINX hop

Add an access log format that records both what an NGINX instance returned and what happened with its upstream. For example:

log_format upstream_trace '$time_iso8601 $remote_addr "$request" '
                          'status=$status request_time=$request_time '
                          'upstream_addr="$upstream_addr" '
                          'upstream_status="$upstream_status" '
                          'upstream_connect_time="$upstream_connect_time" '
                          'upstream_header_time="$upstream_header_time" '
                          'upstream_response_time="$upstream_response_time"';

access_log /var/log/nginx/upstream-trace.log upstream_trace;

Apply the format at each NGINX proxy in the chain, then reload the configuration using your normal deployment process. Confirm that the installed NGINX version supports the variables in the format before enabling it. NGINX documents upstream addresses, statuses, and timing variables and the log module directives and variables.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • $status is the status this NGINX instance sent to its client.
  • $upstream_addr identifies the upstream address or group used for the request; $upstream_status records the status received from upstream attempts.
  • $upstream_connect_time, $upstream_header_time, and $upstream_response_time help show whether time was spent connecting, waiting for headers, or receiving the response.
  • $request_time spans from the first bytes read from the client until the log write after the last response bytes are sent.

If your application already assigns a request ID, log it at every hop and verify that the proxy configuration preserves it upstream. Do not assume that an ID exists or survives the chain. When no shared ID is available, timestamps and request details can help correlate entries, but are less conclusive when traffic is busy.

Reproduce the three outcomes in a controlled lab

Use a test chain with a client, one or more NGINX proxies, and controlled upstream endpoints. Configure logging before sending requests. These are scenarios to exercise, not claims about results from a particular run:

  1. Healthy upstream: Send a request to an endpoint that returns normally. Record the client’s status and correlate it with each proxy’s access-log entry.
  2. Unreachable upstream: Point a test route at an endpoint that cannot be reached. Compare each hop’s $status, upstream fields, and error log to see where the failure appears and whether an earlier proxy passed it along.
  3. Delayed upstream: Use a controlled endpoint that responds slowly enough to exceed the timeout configured for that proxy. Compare the elapsed times and logs at every hop; different layers can have different timeout settings.

For each request, note the client-visible result, then inspect both access and error logs on every proxy. The access log shows the status each instance returned; the error log can provide context about connection failures, timeouts, or other upstream problems.

Rank #2
40 Pcs/20 Set Rack Mount Screws and Cage Nuts for Server Rack Cabinet, Black Carbon Steel M6 x 20 mm Screws with Nylon Washers and Cage Nuts, Rack Mount Hardware for Server Racks/Shelves/Cabinets
  • Durable Carbon Steel: Rack mount screws and cage nuts are made of high-quality carbon steel with a black finish for high strength and dependable durability.
  • Easy Installation: Clear metric threads and uniform pitch for better grip. Nylon washers help secure screws and protect equipment surfaces.
  • Organized Storage: All parts are packed in a portable storage box for easy organization and access.
  • Wide Compatibility: Fits most square-hole racks and cabinets—ideal for server racks, network cabinets, equipment enclosures, and A/V gear.
  • 20-Set Kit: Includes 20 mounting screws with nylon washers (M6 x 20 mm) and 20 square cage nuts—40 pieces in total—meeting daily install and replacement needs.

Correlate the logs without mistaking retries for extra proxies

Match entries using a propagated request ID where available, then compare timestamps, request details, upstream addresses, statuses, and timings. Read the upstream fields as a sequence: a request may involve multiple upstream attempts within one NGINX instance.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Commas can separate attempts. A series of addresses, statuses, or timings may therefore describe retries by one proxy rather than several proxies in the chain.
  • Colons can mark a transition between upstream groups after an internal redirect. Interpret the address and status sequences together rather than treating each value as a separate hop.
  • If $upstream_status is 502, it does not always mean that a reachable server explicitly returned 502. NGINX documents that this variable can hold 502 when no server can be selected; in that case, $upstream_addr holds the upstream group name.

These formats and meanings are documented in the NGINX upstream module reference.

Identify which layer sent the gateway response

Follow the correlated request through the chain from the client-facing proxy toward the upstream. At each NGINX hop, compare its own $status with the next hop’s records. If a proxy logs status=502 or status=504, that instance sent that status downstream. Its upstream fields help establish whether it received an error, encountered an upstream failure, or made multiple attempts. Continue checking adjacent hops to determine whether the response was passed along or generated farther upstream.

A 502 or 504 displayed by the browser is not enough to assign responsibility: an intermediary may forward an upstream error, retry another server, or produce its own gateway response. A 502 is consistent with an upstream that could not be selected or reached, but NGINX also documents upstream queue conditions that can return 502. Confirm the source using each hop’s logs and actual configuration.

Do not attribute every 504 to one particular timeout directive. Timeout settings can differ across layers, and a proxy may pass along a status rather than generate it. Use the timing fields, error logs, and configured timeouts together to identify where the request stalled.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Account for NGINX retry behavior

The documented default for proxy_next_upstream includes error and timeout. Other response codes count as unsuccessful attempts only when configured, and retries are constrained by the configured tries and time limits. NGINX also cannot pass a request to another server after it has started sending the response to the client. Review the effective configuration on the relevant proxy, including proxy_next_upstream and its retry limits, before interpreting a sequence of upstream statuses as a final response. See the NGINX proxy module documentation.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.