You deployed your application, tested it locally, and everything worked perfectly. Then you open your production site and see "502 Bad Gateway" staring back at you. The error appears randomly, sometimes on specific pages, sometimes across the entire site. Let's figure out what's actually happening.
Understanding the 502 Bad Gateway Error
A 502 Bad Gateway means Nginx successfully received your request but couldn't get a valid response from the upstream server. Think of Nginx as a receptionist who can't reach the person you're trying to call. The receptionist (Nginx) is working fine, but something's wrong with the connection to your backend service.
The error typically shows in your browser as:
502 Bad Gateway
nginx/1.24.0And in your Nginx error log (/var/log/nginx/error.log):
2026/04/04 10:15:23 [error] 1234#1234: *5678 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.100, server: example.com, request: "GET /api/users HTTP/1.1", upstream: "http://127.0.0.1:3000/api/users"Step 1: Check If Your Backend Is Running
The most common cause is straightforward: your backend server isn't running. Let's verify:
```bash # Check if your backend process is running # For Node.js apps pm2 list # or ps aux | grep node
# For PHP-FPM systemctl status php8.2-fpm
# For Python/Gunicorn systemctl status gunicorn
# For a generic port check netstat -tlnp | grep :3000 # or with ss ss -tlnp | grep :3000 ```
If the process isn't running, start it. But what if it's running and you still see 502 errors?
Step 2: Verify the Upstream Configuration
Check your Nginx configuration for the upstream block:
cat /etc/nginx/sites-available/example.com | grep -A 10 "upstream"A typical configuration looks like this:
```nginx upstream backend { server 127.0.0.1:3000; keepalive 64; }
server { listen 80; server_name example.com;
location / { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ""; } } ```
Common misconfigurations to check:
- 1.Wrong port number - Your backend runs on port 3001, but Nginx points to 3000
- 2.Wrong IP address - Backend is on a different server or Docker container
- 3.**Missing
proxy_http_version 1.1** - Needed for keepalive connections
Step 3: Test the Backend Directly
Bypass Nginx and test your backend directly:
```bash # Test with curl curl -I http://127.0.0.1:3000/
# Test from inside a Docker container docker exec nginx-container curl -I http://backend-service:3000/
# Test with full request curl -v http://127.0.0.1:3000/api/health ```
If the backend responds correctly, the issue is in the Nginx-to-backend connection. If it fails, fix the backend first.
Step 4: Check Unix Socket Permissions (PHP-FPM)
If you're using PHP-FPM with a Unix socket, permission issues cause 502 errors:
# Check the socket file
ls -la /run/php/php8.2-fpm.sockOutput showing the problem:
``
srw-rw---- 1 root root 0 Apr 4 10:00 /run/php/php8.2-fpm.sock
The socket is owned by root with no read/write for the nginx user. Fix it:
Option 1: Change socket permissions in PHP-FPM config
Edit /etc/php/8.2/fpm/pool.d/www.conf:
listen.owner = www-data
listen.group = www-data
listen.mode = 0660Then restart PHP-FPM:
systemctl restart php8.2-fpmOption 2: Add nginx user to the socket's group
usermod -aG www-data nginx
# Restart services
systemctl restart nginxStep 5: Check for Port Binding Issues
Your backend might be binding to a different interface:
# See what's actually listening
ss -tlnp | grep 3000Output:
``
LISTEN 0 128 127.0.0.1:3000 0.0.0.0:* users:(("node",pid=1234,fd=18))
If it shows 127.0.0.1:3000, it only accepts local connections. If Nginx runs in a Docker container trying to connect to the host, use:
upstream backend {
server host.docker.internal:3000;
}Or for Linux where host.docker.internal doesn't work:
upstream backend {
server 172.17.0.1:3000; # Docker bridge gateway
}Step 6: Handle Connection Refused vs Timed Out
Different error messages require different fixes:
Connection refused - Nothing is listening:
``
connect() failed (111: Connection refused)
``
Fix: Start the backend service or fix the port.
Connection timed out - Backend is overwhelmed or unreachable:
``
connect() failed (110: Connection timed out)
``
Fix: Increase timeout values or scale your backend.
Add these to your location block:
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;Step 7: Check for SELinux Issues (RHEL/CentOS)
On systems with SELinux enabled, Nginx might be blocked from network connections:
```bash # Check if SELinux is blocking ausearch -m avc -ts recent | grep nginx
# Allow Nginx to make network connections setsebool -P httpd_can_network_connect 1
# Allow connections to specific ports setsebool -P httpd_can_network_connect_on 1 ```
Verification Steps
After making changes, verify everything works:
```bash # Test Nginx configuration nginx -t
# Reload Nginx systemctl reload nginx
# Check the error log for new errors tail -f /var/log/nginx/error.log
# Test from a browser or curl curl -I https://example.com/ ```
Quick Reference: Error Messages and Solutions
| Error Message | Cause | Solution |
|---|---|---|
Connection refused | Backend not running | Start backend service |
Permission denied | Socket permissions | Fix socket ownership |
No such file or directory | Socket missing | Start PHP-FPM or check path |
Connection timed out | Backend slow/down | Scale backend or fix network |
Connection reset by peer | Backend crashed | Check backend logs |
The 502 Bad Gateway is almost always a communication problem between Nginx and your backend. Methodically checking each layer—process running, correct port, permissions, and network connectivity—will lead you to the root cause.