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:

bash
502 Bad Gateway
nginx/1.24.0

And in your Nginx error log (/var/log/nginx/error.log):

bash
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:

bash
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. 1.Wrong port number - Your backend runs on port 3001, but Nginx points to 3000
  2. 2.Wrong IP address - Backend is on a different server or Docker container
  3. 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:

bash
# Check the socket file
ls -la /run/php/php8.2-fpm.sock

Output 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:

ini
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Then restart PHP-FPM:

bash
systemctl restart php8.2-fpm

Option 2: Add nginx user to the socket's group

bash
usermod -aG www-data nginx
# Restart services
systemctl restart nginx

Step 5: Check for Port Binding Issues

Your backend might be binding to a different interface:

bash
# See what's actually listening
ss -tlnp | grep 3000

Output: `` 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:

nginx
upstream backend {
    server host.docker.internal:3000;
}

Or for Linux where host.docker.internal doesn't work:

nginx
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:

nginx
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 MessageCauseSolution
Connection refusedBackend not runningStart backend service
Permission deniedSocket permissionsFix socket ownership
No such file or directorySocket missingStart PHP-FPM or check path
Connection timed outBackend slow/downScale backend or fix network
Connection reset by peerBackend crashedCheck 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.