Why 502 Bad Gateway errors happen in production
A 502 Bad Gateway error means that a server acting as a gateway or reverse proxy received an invalid response from an upstream server, honestly. In a typical production architecture, Nginx sits between the client and the application. The browser successfully reaches Nginx, but Nginx cannot successfully communicate with the application behind it, basically.
This is why a 502 error is different from an application returning a normal HTTP 500 response, you know? With a 500 response, the application itself received the request and generated an error. With a 502 response, Nginx is usually unable to obtain a valid response from the upstream application, which is a mess.
The upstream application might have crashed, stopped listening on the expected port, refused the connection, become overloaded, been incorrectly configured, or become unreachable because of Docker networking or firewall problems, basically.
A 502 error usually means the client can reach Nginx, but Nginx cannot successfully reach the application behind it, trust me.
Understanding a typical production architecture
Before troubleshooting a 502 error, identify the complete request path, honestly. A modern application may contain several layers between the browser and the application process, basically.
- ●
Browser or API client
- ●
DNS
- ●
CDN or load balancer
- ●
Firewall
- ●
Nginx reverse proxy
- ●
Docker container or system service
- ●
Application server
- ●
Database or external service, you know?
The more layers exist between the client and application, the more important it becomes to identify exactly where the request fails, seriously. A 502 generated by Nginx is usually much easier to diagnose once you can prove whether the upstream application is reachable directly, basically.
The most common causes of Nginx 502 errors
| Problem | Typical symptom | Severity |
|---|---|---|
| Application crashed | Nginx cannot connect to upstream | Critical |
| Wrong upstream port | Connection refused | Critical |
| Application not listening | Connection refused | Critical |
| Docker networking issue | Upstream host unreachable | High |
| Application timeout | Gateway timeout or intermittent 502 | High |
| Server overload | Random or increasing 502 errors | Critical |
| Bad Nginx configuration | 502 after deployment | High |
| Unix socket failure | Socket connection error | High |
The first thing to check: Nginx error logs
The Nginx error log is usually the fastest way to identify the cause of a 502 error, honestly. Instead of guessing whether the application, port, network, or configuration is responsible, inspect the exact error Nginx recorded, basically.
sudo tail -f /var/log/nginx/error.log
Generate the 502 error while watching the log, you know? The new entry will often immediately reveal whether Nginx received a connection refusal, timeout, DNS failure, broken pipe, or invalid upstream response, which is huge.
sudo journalctl -u nginx --since "10 minutes ago"
💡 Fast diagnosis
Do not start by changing Nginx configuration, seriously. First reproduce the 502 error and inspect the Nginx error log. The error message often tells you exactly which layer is failing, basically.
Checking whether the application is running
The next step is to verify that the upstream application is actually running, honestly. A surprisingly large number of 502 incidents are caused by an application process that crashed, was killed, failed during startup, or was never started after deployment, which is a mess.
ps aux | grep dotnet
ps aux | grep node
ps aux | grep java
The exact command depends on the technology used by your application, basically. The goal is simply to determine whether the expected process exists and whether it has been running continuously, you know?
sudo systemctl status my-api
sudo journalctl -u my-api --since "30 minutes ago"
If the application is managed by systemd, inspect both its current status and recent logs, seriously. A service may appear stopped because of a startup exception, missing environment variable, invalid configuration, unavailable database, or incorrect file permissions, basically.
Checking which port the application is listening on
A common production mistake is configuring Nginx to proxy traffic to the wrong port, honestly. For example, the application may listen on port 5000 while Nginx attempts to connect to port 5001, which is bad.
sudo ss -lntp
Look for the port on which your application is actually listening, basically. You should then compare that value with the proxy_pass configuration in Nginx, you know?
location / {
proxy_pass http://127.0.0.1:5000;
}
If the application listens on 5000 but Nginx points to 5001, Nginx will normally receive a connection refused error and return a 502 response to the client, seriously.
Testing the upstream application directly
One of the most useful troubleshooting techniques is to bypass Nginx temporarily and connect directly to the upstream application, honestly. This separates application problems from reverse proxy problems, basically.
curl -v http://127.0.0.1:5000/
If this request fails, the problem is probably between the operating system and the application, you know? If the direct request succeeds but the public HTTPS request returns 502, the problem is more likely related to Nginx, networking, DNS, or another proxy layer, which is a mess.
curl -v http://127.0.0.1:5000/health
💡 Isolation technique
Always try to establish whether the upstream application works without Nginx, basically. This single test can eliminate a large part of the troubleshooting tree, trust me.
Nginx upstream configuration
Nginx commonly forwards requests using proxy_pass, honestly. A small configuration mistake can make the application completely unreachable from Nginx, which is bad.
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
When troubleshooting, verify the hostname, IP address, port, protocol, and location block, basically. Also confirm that the configuration you edited is actually included in the active Nginx configuration, you know?
sudo nginx -t
sudo nginx -T
The nginx -T command prints the complete active configuration, seriously. This is useful when multiple configuration files exist and you are not sure which server block is handling the request, basically.
Docker and container networking problems
Docker introduces another common source of 502 errors, honestly. Nginx may be running on the host while the application runs inside a container, or both services may run inside separate containers, basically.
A frequent mistake is using localhost incorrectly, you know? Inside a container, localhost refers to that container itself. It does not automatically refer to another Docker container or the host machine, which is annoying.
services:
nginx:
image: nginx:latest
depends_on:
- api
api:
image: my-api:latest
expose:
- "5000"
When Nginx and the API are on the same Docker network, Nginx can usually communicate with the API using the service name rather than localhost, basically.
location / {
proxy_pass http://api:5000;
}
docker ps
docker network ls
docker network inspect my-network
Verify that both containers are running and attached to the same network, honestly. Also verify that the application is listening on the expected interface and port inside the container, you know?
Connection refused versus connection timeout
The exact Nginx error message matters, basically. A connection refused error and a connection timeout usually point to different underlying problems, you know?
| Error | Likely cause |
|---|---|
| Connection refused | Application is stopped or wrong port |
| Connection timed out | Network, firewall, overload, or unreachable host |
| Host not found | DNS or upstream hostname problem |
| Connection reset | Application or network closed connection |
| Upstream prematurely closed connection | Application terminated connection unexpectedly |
Understanding this distinction makes troubleshooting much faster, honestly. For example, if Nginx receives connection refused from 127.0.0.1:5000, changing firewall rules is unlikely to solve the problem. The application probably is not listening on that port, basically.
Application crashes and startup failures
An application can be running perfectly one minute and then start returning 502 errors because the process crashed, which is a mess. Nginx itself may remain healthy, which makes the problem appear to be an Nginx issue, honestly.
sudo journalctl -u my-api --since "1 hour ago"
docker logs --tail 200 api-container
Look for out-of-memory errors, unhandled exceptions, database connection failures, invalid environment variables, missing configuration files, failed migrations, and startup dependency failures, basically.
If the application repeatedly starts and crashes, Nginx may produce intermittent 502 errors, you know? The real issue is not the proxy; it is the instability of the upstream process, seriously.
Server overload and resource exhaustion
A server can produce 502 errors even when the application process appears to be running, basically. High CPU usage, memory exhaustion, disk pressure, connection limits, or excessive traffic can prevent the application from responding reliably, which is bad.
uptime
free -h
df -h
top
Pay particular attention to available memory, honestly. When Linux runs out of memory, the operating system may terminate application processes through the OOM killer, you know?
dmesg -T | grep -i "out of memory"
dmesg -T | grep -i "killed process"
If Nginx is healthy but the application repeatedly disappears under load, treat the incident as a capacity or application stability problem rather than simply increasing Nginx timeouts, basically.
Nginx timeout configuration
Some applications legitimately require more time to complete requests, honestly. Long-running reports, file processing, large exports, and certain API operations can exceed default proxy timeout values, basically.
location / {
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_pass http://127.0.0.1:5000;
}
Increasing timeouts can be appropriate, but it should not be the first response to every 502 incident, you know? Extremely long timeouts can allow slow requests to consume workers and connections, potentially making an overloaded system even worse, which is a mess.
💡 Timeout rule
Fix slow application behavior before increasing proxy timeouts whenever possible, seriously. A timeout configuration should reflect expected application behavior, not hide an unhealthy backend, basically.
Unix socket problems
Some production systems use Unix sockets instead of TCP ports, honestly. This can provide efficient local communication, but socket permissions and file paths become additional failure points, basically.
location / {
proxy_pass http://unix:/run/my-api/app.sock;
}
sudo ls -la /run/my-api/
sudo ss -xl
If the socket file does not exist, has incorrect permissions, or is created in a different directory after deployment, Nginx may return 502 errors even though the application process is running, you know?
DNS problems between Nginx and the upstream
When Nginx proxies to a hostname instead of a local IP address, DNS becomes another dependency, basically. If the upstream hostname cannot be resolved, Nginx cannot establish the backend connection, which is bad.
getent hosts api.internal.example.com
dig api.internal.example.com
This is especially relevant in containerized and cloud environments where service discovery and internal DNS are commonly used, honestly.
Checking firewall and network connectivity
If Nginx and the application are on different machines, network connectivity must be verified independently from Nginx configuration, basically.
nc -vz 10.0.0.20 5000
curl -v http://10.0.0.20:5000/health
If the TCP connection cannot be established, inspect firewall rules, cloud security groups, network ACLs, routing, private network configuration, and the interface on which the application is listening, you know?
An application listening only on 127.0.0.1 cannot normally be reached from another machine, seriously. If the reverse proxy and application are on separate servers, the application must listen on an interface reachable by the proxy while still being protected from unnecessary public access, basically.
Nginx configuration validation and reload
After changing an Nginx configuration, always validate it before reloading the service, honestly.
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx
A reload is normally preferable to a complete restart because existing connections can be handled more gracefully, basically. If nginx -t fails, do not reload until the configuration problem has been corrected, you know?
Checking the complete request path
A useful production troubleshooting method is to test the request at every layer instead of testing only the public URL, seriously.
- ●
Test the application directly on localhost
- ●
Test the application using its internal IP
- ●
Test the application through its Docker service name
- ●
Test Nginx locally
- ●
Test the public HTTP endpoint
- ●
Test the public HTTPS endpoint
- ●
Test through the CDN or load balancer, basically
Each successful test eliminates another layer from the list of possible causes, honestly. This is much more reliable than repeatedly changing configuration and hoping the 502 disappears, trust me.
Production incident response workflow
- ●
Confirm the affected hostname and endpoint
- ●
Determine whether all users are affected
- ●
Check Nginx error logs
- ●
Check whether Nginx itself is healthy
- ●
Check whether the application process is running
- ●
Check the application logs
- ●
Verify the upstream IP and port
- ●
Test the upstream directly
- ●
Check Docker containers and networks if applicable
- ●
Check firewall and network connectivity
- ●
Check CPU and memory usage
- ●
Validate Nginx configuration
- ●
Reload Nginx if configuration changes are required
- ●
Test the public endpoint
- ●
Monitor the system after recovery
- ●
Identify and document the root cause, basically
The fastest path to resolving a 502 is to identify whether the upstream application is reachable, honestly. Once that is known, the investigation becomes much more focused, basically.
Common mistakes when fixing 502 errors
- ●
Restarting Nginx without checking the error log
- ●
Increasing timeouts without investigating application performance
- ●
Changing ports without checking which port the application actually uses
- ●
Using localhost incorrectly inside Docker
- ●
Ignoring application logs
- ●
Checking only the public URL
- ●
Changing multiple configuration files at the same time
- ●
Disabling security controls to make connectivity work
- ●
Ignoring memory and CPU exhaustion
- ●
Assuming every 502 is caused by Nginx, basically
The most dangerous troubleshooting pattern is repeatedly restarting services without identifying the root cause, seriously. Restarting an application can temporarily restore service while leaving the underlying memory leak, crash, bad configuration, or dependency failure unresolved, which is a mess.
Prevention strategy
Preventing 502 errors requires more than a correct Nginx configuration, honestly. The application, infrastructure, deployment process, and monitoring system all need to work together, basically.
- ●
Monitor application availability
- ●
Monitor Nginx error rates
- ●
Monitor CPU and memory
- ●
Use application health checks
- ●
Configure service restart policies carefully
- ●
Use Docker health checks when applicable
- ●
Validate Nginx configuration during deployment
- ●
Test upstream connectivity after deployment
- ●
Use consistent production configuration
- ●
Monitor container restarts
- ●
Monitor database availability
- ●
Set appropriate proxy timeouts
- ●
Document the production architecture
- ●
Maintain a tested rollback procedure, basically
Health checks are especially valuable because they can detect an application that is technically running but unable to serve useful traffic, you know? A process existing in the process list does not necessarily mean the application is healthy, basically.
A reliable production system does not only detect when Nginx is down, seriously. It detects when the entire request path between the client and application is broken, basically.
Production 502 checklist
- ●
Nginx process is running
- ●
Nginx configuration is valid
- ●
Upstream application is running
- ●
Application is listening on the expected port
- ●
Nginx uses the correct upstream address
- ●
Docker containers are running
- ●
Docker networking is correct
- ●
Firewall rules allow backend traffic
- ●
DNS resolves the upstream correctly
- ●
Application health endpoint responds
- ●
CPU usage is within acceptable limits
- ●
Memory usage is within acceptable limits
- ●
Disk space is available
- ●
Application logs contain no recurring crashes
- ●
Nginx logs contain no recurring upstream failures
- ●
Timeouts match expected application behavior
- ●
All production nodes use consistent configuration
- ●
Monitoring detects recurring 502 responses
- ●
Deployment validates the complete request path
- ●
Rollback procedures are documented, basically
Frequently asked questions
What does Nginx 502 Bad Gateway mean?
Is a 502 error caused by Nginx?
What should I check first when I see a 502?
Why does curl localhost work but the public website returns 502?
Why does localhost not work between Docker containers?
Should I increase proxy_read_timeout when I get 502 errors?
Why does restarting Nginx temporarily fix the problem?
Can low memory cause 502 errors?
Can Docker cause intermittent 502 errors?
What is the difference between 500 and 502?
What is the difference between 502 and 504?
How can I prevent 502 errors after deployments?
Final thoughts
Nginx 502 Bad Gateway errors are one of the most common production symptoms in reverse-proxy architectures, basically. The error itself is simple, but the underlying cause can exist anywhere between Nginx and the application, you know?
The most effective troubleshooting approach is systematic: inspect the Nginx error log, verify the application process, confirm the listening port, test the upstream directly, inspect networking, and only then modify the proxy configuration, honestly.
Once the service has recovered, do not stop at restarting the application, seriously. Determine why the upstream became unavailable. If it crashed, investigate the crash. If it ran out of memory, investigate resource usage. If the port changed, improve deployment validation. If Docker networking failed, improve health checks and service configuration, basically.
A 502 error is the symptom, honestly. The real goal of production troubleshooting is to find the reason the upstream service became unavailable and make sure the same failure cannot silently happen again, basically.
