WIUNIX ACADEMY
Nginx 502 and 504: identify the failing upstream phase
Separate connection refusal, upstream queueing, slow response headers and proxy timeouts using bounded probes and correlated timing.
Make this guide yoursYOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
USE YOUR OWN VALUES
Configure this tutorial
Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.
Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.
Set values for my environment5 editable values
THE OUTCOME
What will you have at the end?
Separate connection refusal, upstream queueing, slow response headers and proxy timeouts using bounded probes and correlated timing.
Supported operating systems and versions
Primary-documentation review; no production execution or universal installation test is claimed. Examples assume existing tools on Linux and must be adapted to authorized deployment context.
Before you begin
- Authorized operator access, existing tools named in the panels, and a private place to retain diagnostic evidence.
- Use a staging environment or an approved read-only production investigation; review disruptive changes separately.
A status code is a symptom, not a root cause
A 502 usually means the gateway could not obtain a usable upstream response; a 504 means its wait expired. Neither tells you whether the fault is a refused TCP connection, an overloaded worker pool, an invalid protocol response or a deadline imposed by another proxy. Work on one known read-only endpoint and one UTC time window. This guide assumes host Nginx proxies plain HTTP to one known address. FastCGI, gRPC, Unix sockets and a container-only network need their own transport checks.
LET’S BUILD
Check the selected distribution and required tools first
Run on the authorized diagnostic host or disposable lab VM. Compare the installed OS and required packages below with the selected path. Obtain missing tools from the distribution’s enabled official repositories through your approved package-management process; this workflow does not reinstall an existing server or switch its repository.
Debian 13 and 12 use the package names below. Debian 12 is in LTS; architecture and individual package support must be checked rather than inferred from the major version.
An existing Nginx installation is required. Packaged deployments normally use nginx.service and nginx.conf under /etc/nginx, but discover active includes and logs from the effective configuration. Do not assume Ubuntu sites-enabled layout on an RPM host.
Effective configuration can contain private deployment data; keep it private. Set this guide’s error-log field to the actual configured destination.
Authorized terminal on the host identified in this section
cat /etc/os-release
dpkg-query -W curl iproute2
command -v curl ss nginx
sudo nginx -t
sudo nginx -T 2>&1 | sed -n '1,100p'
systemctl show nginx.service -p FragmentPath -p DropInPaths -p ExecStartRequired packages and tools are identified; resolve missing tools before continuing.
LET’S BUILD
Record versions and the exact endpoint
On the proxy host, record time and Nginx build, then request the authorized public hostname without credentials or query parameters. The response header timing includes DNS, TCP and TLS effects on this path; it is not an application-only measurement. Use an existing harmless root endpoint, or adapt the URL to an approved health route before running.
Authorized Linux terminal
date -u +'%Y-%m-%dT%H:%M:%SZ'
nginx -v
curl --noproxy '*' --connect-timeout 3 --max-time 15 -sS -o /dev/null -w 'status=%{http_code} connect=%{time_connect} tls=%{time_appconnect} first_byte=%{time_starttransfer} total=%{time_total}\n' 'https://app.example.com/'Record the HTTP status or curl transport error with the UTC timestamp. A timeout at 15 seconds is the probe deadline, not proof of Nginx’s own timeout.
LET’S BUILD
Check host policy independently
Inspect kernel messages in the same failure window. On a host with active AppArmor profiles, a denial can be independent of Unix permissions or network reachability. Do not disable the profile just to pass the check; correlate it with application logs and the actual host policy.
Authorized terminal on the host identified in this section
sudo journalctl -k --since '-10 min' --no-pager -n 120Any suspected policy failure is tied to specific evidence; enforcement and firewall configuration remain unchanged.
LET’S BUILD
Bypass the proxy without changing exposure
From the Nginx host, call the existing private backend with the same Host value. This is an authorized read-only probe, not permission to publish a private port. The HTTP Host may select a virtual application; HTTPS upstreams require verified TLS/SNI instead of this plain-HTTP example.
Authorized Linux terminal
curl --noproxy '*' --connect-timeout 3 --max-time 15 -H 'Host: app.example.com' -sS -o /dev/null -w 'status=%{http_code} connect=%{time_connect} first_byte=%{time_starttransfer} total=%{time_total}\n' 'http://127.0.0.1:8000/'A repeatable private response establishes a comparison. Immediate refusal differs from a connection timeout and from a slow first byte.
LET’S BUILD
Separate a missing listener from a saturated application
On the upstream host, inspect listeners and the application unit. The port must match the actual proxy configuration; a process listening only in another network namespace is not a host listener. A unit marked active can still serve errors or queue requests. Avoid repeatedly restarting the process before collecting its recent failure evidence.
Authorized Linux terminal
sudo ss -lntp 'sport = :8000'
sudo systemctl status 'example-app.service' --no-pager
sudo journalctl -u 'example-app.service' --since '-10 min' --no-pager -n 100Match the exact PID/address/port and recent application errors. Logs may contain private values; review locally and redact before sharing.