What does 502 Bad Gateway mean?
A 502 Bad Gateway response usually means that Nginx could not obtain a valid response from the application or service behind it.
It does not necessarily mean Nginx itself is down. If Nginx can display a 502 page, it has generally accepted the request but failed to communicate correctly with the backend service.
User → Nginx → Backend application → Database or other servicesA diagnostic sequence for the first five minutes
Validate the configuration first, then inspect the actual upstream error in the Nginx error log and confirm the address on which the backend is listening. Replace PORT with your upstream port.
Run the commands in order. The first failed check usually identifies the layer that needs investigation.
sudo nginx -t
sudo tail -n 80 /var/log/nginx/error.log
sudo ss -lntp
curl -sv --max-time 5 http://127.0.0.1:PORT/health- Successful nginx -t: syntax is ok and test is successful; otherwise fix the reported file and line first.
- Connection refused: no process is listening on the target, or the IP/port is wrong.
- Connection timed out: investigate the firewall, network path or an unresponsive backend.
- HTTP/1.1 200: the backend responds locally; compare the Nginx upstream address, protocol and Host header.
- HTTP 500/503: connectivity works; the root cause is probably in the application or one of its dependencies.
Interpret the Nginx error log
The text on the 502 page does not reveal the root cause. The upstream record from the same second in the error log does. This command filters the most useful signatures.
sudo grep -E "connect() failed|timed out|prematurely closed|no live upstreams|Permission denied" \
/var/log/nginx/error.log | tail -n 50- connect() failed (111: Connection refused): backend is down or the address/port is wrong.
- upstream timed out: the backend may accept connections but does not return a response in time.
- upstream prematurely closed connection: the application closed the connection before completing a valid HTTP response.
- no live upstreams: every target in the upstream group is unavailable.
- Permission denied while connecting to upstream: inspect Unix socket, SELinux and directory permissions.
Verify a backend managed by systemd
If the backend is a systemd service, do not rely on the active label alone. Review recent logs and verify the listening port. Replace APP_SERVICE and PORT for your environment.
sudo systemctl status APP_SERVICE --no-pager
sudo journalctl -u APP_SERVICE --since "15 minutes ago" --no-pager
sudo ss -lntp | grep ':PORT'
curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' http://127.0.0.1:PORT/health- Active service + listening port + 200: continue with the Nginx proxy configuration.
- Failed service or increasing restart count: solve the application startup error before restarting Nginx.
- Service is active but no port is open: it may bind elsewhere, use a socket or not be ready yet.
Test backend access from an Nginx container
When Nginx runs in a container, localhost means the Nginx container itself. Test from Nginx's network context rather than only from the host.
Replace NGINX_CONTAINER, BACKEND_SERVICE and PORT with your Compose values.
docker compose ps
docker compose logs --tail=100 BACKEND_SERVICE
docker inspect NGINX_CONTAINER --format '{{json .NetworkSettings.Networks}}'
docker inspect BACKEND_SERVICE --format '{{json .NetworkSettings.Networks}}'
docker exec NGINX_CONTAINER sh -c 'wget -S -O- http://BACKEND_SERVICE:PORT/health'- If the inspect outputs have no shared network, the containers cannot resolve each other by service name.
- Bad address or could not resolve host: service name or Docker DNS/network attachment is wrong.
- Connection refused: name resolution works but the backend is not listening on that port.
- 200 OK: the container network works; inspect the Nginx location and proxy_pass match.
Compare the active Nginx configuration
The file you edited may differ from the configuration Nginx actually loaded. nginx -T prints the full active configuration including all included files.
sudo nginx -T 2>&1 | grep -nE 'server_name|location|proxy_pass|upstream'
location / {
proxy_pass http://127.0.0.1:3000;
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;
}- The proxy_pass target must match the address verified by ss or the Docker connectivity test.
- Do not use https in proxy_pass if the backend listens with HTTP.
- After a change, run sudo nginx -t first and use sudo systemctl reload nginx only if the test succeeds.
The backend application is unavailable
Nginx forwards requests to an IP address, port or Unix socket. If the application has stopped, is restarting continuously or is not listening on the expected port, Nginx cannot establish a valid connection.
Restarting Nginx alone rarely provides a permanent solution. The reason the upstream application became unavailable must be identified.
- Application did not start after deployment
- Container is continuously restarting
- Service is listening on the wrong port
- Process was terminated because of memory pressure
- Application is running but not ready to receive traffic
Incorrect proxy_pass address or port
Nginx cannot reach the backend if the configured address, port or protocol is incorrect. The application port may have changed while the Nginx configuration remained unchanged.
Connecting with HTTPS to a service that expects HTTP, or HTTP to a service that expects HTTPS, can also prevent Nginx from receiving a valid response.
Docker network or service-name problems
When Nginx and the application run in separate containers, localhost refers to the Nginx container itself—not the backend application.
A container being marked Up is not sufficient. Connectivity must be verified from the network context in which Nginx is running.
- Containers are not attached to the same network
- Compose service name has changed
- Backend container failed to start
- Application listens only on 127.0.0.1
- Nginx is using an outdated IP address
The backend closes the connection early
Nginx may connect to the backend, but the application can close the connection before returning a valid HTTP response. The error log may contain upstream prematurely closed connection.
This message only confirms that the connection ended unexpectedly. The actual root cause is usually found in the application logs from the same time window.
- Unhandled application exception
- Worker process crash
- Memory exhaustion
- Application-level timeout
- Database connection problem
- Process termination during deployment
Unix socket permissions
Nginx can communicate with PHP-FPM, Gunicorn and similar services through a Unix socket. Even when the socket exists, the Nginx worker user may not have permission to access it.
Granting broad write permissions without understanding ownership can hide the symptom temporarily while introducing a serious security risk.
- Socket owner and group
- File and parent-directory permissions
- Nginx worker user
- Application socket creation settings
Resource exhaustion
A backend can appear to be running while CPU, memory, disk or connection limits prevent it from serving requests.
Increasing timeout values in this situation can make users wait longer without addressing the actual bottleneck.
- OOM events and memory pressure
- Full disk or exhausted inodes
- Sustained CPU saturation
- Exhausted database connection pool
- Insufficient worker capacity
- File descriptor limits
The difference between 502 and 504
502 Bad Gateway indicates that Nginx did not receive a valid response from the upstream. 504 Gateway Timeout indicates that the upstream did not respond within the expected time.
The HTTP status alone is not enough to determine the root cause. Nginx logs, application logs and the incident timeline must be evaluated together.
Safe initial checks
Before changing a production environment, establish the scope of the failure, when it began and whether it correlates with a recent change.
- Does the error affect every URL or one endpoint?
- Is the backend listening on the expected address and port?
- Can Nginx reach the backend from its own environment?
- Did the error begin after a deployment?
- What do Nginx and application logs show in the same time window?
- Is there CPU, memory, disk or connection pressure?
- Is the problem constant or traffic-dependent?
Interventions to avoid
Changes made before collecting evidence can conceal the root cause or expand the outage.
- Restarting Nginx repeatedly
- Increasing every timeout value
- Opening socket permissions indiscriminately
- Disabling the firewall completely
- Deleting containers and volumes
- Rolling back before preserving relevant logs
When should you seek specialist support?
If the error recurs intermittently, affects multiple services or involves a risk of downtime or data loss, it should not be treated as a single Nginx setting.
A permanent resolution often requires Nginx, the application, container networking, databases and system resources to be examined on the same timeline.
Common questions about Nginx 502
Will restarting Nginx fix a 502 error?
It may clear some temporary states, but it will not provide a lasting solution if the backend is unavailable or resource-constrained.
Should I increase the timeout?
It can be appropriate for an intentionally long-running operation. If the service has crashed or is blocked, it only delays the visible failure.
Can a 502 error be caused by the user?
It is usually generated by the server or upstream service. If it occurs only for specific requests, request size, headers and application input handling should also be examined.