troubleshooting2025-06-18·8·19/348

Fixing nginx 502 Bad Gateway Error

Complete guide to diagnosing and resolving nginx 502 Bad Gateway errors, including upstream connection issues, timeout configurations, and PHP-FPM fixes.

Fixing nginx 502 Bad Gateway Error

The 502 Bad Gateway error is nginx's way of saying it cannot reach the upstream server. During a deployment in Lisbon, this error appeared intermittently and was difficult to reproduce. This guide covers systematic diagnosis and multiple fixes.

Environment

  • OS: Ubuntu 22.04 LTS
  • Web server: nginx 1.18.0
  • Upstream: PHP-FPM 8.1 (via Unix socket)
  • Application: WordPress site
$ nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

$ php-fpm8.1 -v
PHP 8.1.2-1ubuntu2.14 (cli) (built: Jun 13 2023 13:47:39) (NTS)

The Problem

$ curl -I http://localhost
HTTP/1.1 502 Bad Gateway
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 2025-06-18 10:00:00 GMT

# Check nginx error log
$ sudo tail -f /var/log/nginx/error.log
2025/06/18 10:00:00 [error] 1234#1234: *1 connect() to unix:/run/php/php8.1-fpm.sock failed (11: Resource temporarily unavailable)
2025/06/18 10:00:00 [error] 1234#1234: *1 upstream prematurely closed connection while reading response header from upstream

Analysis

Step 1: Check PHP-FPM Status

$ sudo systemctl status php8.1-fpm
● php8.1-fpm.service - The PHP FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2025-06-18 09:55:00 WET; 5min ago
    Process: 1234 ExecStart=/usr/sbin/php-fpm8.1 --nodaemonize (code=exited, status=0/SUCCESS)
   Main PID: 1235 (php-fpm8.1)
     Memory: 256.0M
        CPU: 1.234s

# Check if socket exists
$ ls -la /run/php/php8.1-fpm.sock
srw-rw---- 1 www-data www-data 0 Jun 18 09:55 /run/php/php8.1-fpm.sock

# Check PHP-FPM process count
$ ps aux | grep php-fpm | wc -l
5

Step 2: Check nginx Configuration

$ cat /etc/nginx/sites-available/default
server {
    listen 80;
    server_name localhost;
    root /var/www/html;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
}

Step 3: Test the Socket Connection

# Test if PHP-FPM is actually listening
$ sudo php-fpm8.1 -tt
[18-Jun-2025 10:00:00] configuration file /etc/php/8.1/fpm/php-fpm.conf test is successful

# Check socket connectivity
$ sudo nc -U /run/php/php8.1-fpm.sock
# If it connects and hangs, socket is working
# Press Ctrl+C to exit

Step 4: Check Worker Limits

# Check current PHP-FPM pool configuration
$ cat /etc/php/8.1/fpm/pool.d/www.conf | grep -E "^(pm|pm\.max_children|pm\.start_servers)"
pm = dynamic
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500

# Check current active connections
$ sudo ss -x | grep php | wc -l
# Number of active PHP-FPM workers

Step 5: Check System Resources

# Check file descriptors
$ cat /proc/sys/fs/file-nr
1024    0   65536

# Check open files for PHP-FPM
$ sudo ls /proc/$(pgrep -o php-fpm)/fd | wc -l
45

# Check ulimit
$ ulimit -n
1024

Solution

Fix 1: Increase PHP-FPM Workers

# Edit pool configuration
$ sudo nano /etc/php/8.1/fpm/pool.d/www.conf

# Increase max_children based on available RAM
# Each PHP-FPM worker uses ~20-50MB
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 500

# Restart PHP-FPM
$ sudo systemctl restart php8.1-fpm

Fix 2: Configure nginx Upstream Timeouts

$ sudo nano /etc/nginx/sites-available/default

server {
    listen 80;
    server_name localhost;
    
    # Increase timeouts for slow PHP scripts
    fastcgi_read_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_connect_timeout 300;
    
    # Buffer settings
    fastcgi_buffer_size 128k;
    fastcgi_buffers 4 256k;
    fastcgi_busy_buffers_size 256k;
    
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
}

# Test and reload
$ sudo nginx -t
$ sudo systemctl reload nginx

Fix 3: Increase System Limits

# Increase file descriptor limits
$ sudo nano /etc/security/limits.conf
www-data soft nofile 65535
www-data hard nofile 65535

# Increase in PHP-FPM config
$ sudo nano /etc/php/8.1/fpm/pool.d/www.conf
listen.backlog = 65535

# Increase system-wide
$ sudo sysctl -w net.core.somaxconn=65535
$ sudo sysctl -w net.ipv4.tcp_max_syn_backlog=65535

# Make persistent
$ echo "net.core.somaxconn = 65535" | sudo tee -a /etc/sysctl.conf
$ echo "net.ipv4.tcp_max_syn_backlog = 65535" | sudo tee -a /etc/sysctl.conf

Fix 4: Switch to TCP Socket (Alternative)

# Edit PHP-FPM pool to use TCP instead of Unix socket
$ sudo nano /etc/php/8.1/fpm/pool.d/www.conf

; Old: listen = /run/php/php8.1-fpm.sock
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1

# Edit nginx config
$ sudo nano /etc/nginx/sites-available/default

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass 127.0.0.1:9000;
}

# Restart both services
$ sudo systemctl restart php8.1-fpm
$ sudo nginx -t && sudo systemctl reload nginx

Fix 5: Monitor Connection Queue

# Create a monitoring script
#!/bin/bash
# /usr/local/bin/php-fpm-monitor.sh

while true; do
    ACTIVE=$(sudo ss -x | grep php | wc -l)
    QUEUED=$(sudo ss -x -l | grep php | awk '{print $2}')
    TIMESTAMP=$(date +%H:%M:%S)
    
    echo "${TIMESTAMP} Active: ${ACTIVE}, Queued: ${QUEUED}"
    
    if [ "$ACTIVE" -gt 15 ]; then
        echo "WARNING: High PHP-FPM worker count!"
    fi
    
    sleep 5
done

Quick Diagnostic Commands

# Check nginx error log
$ sudo tail -20 /var/log/nginx/error.log

# Check PHP-FPM error log
$ sudo tail -20 /var/log/php8.1-fpm.log

# Test nginx config
$ sudo nginx -t

# Check socket
$ sudo ss -x | grep php

# Check worker count
$ ps aux | grep php-fpm | grep -v grep | wc -l

Lessons Learned

  1. 502 Bad Gateway means upstream failure - always check the upstream server first.
  2. PHP-FPM worker exhaustion is the most common cause - increase pm.max_children.
  3. Monitor worker count in production to catch exhaustion before it causes errors.
  4. Unix sockets are faster but TCP sockets are easier to debug.
  5. Set appropriate timeouts - default nginx timeouts are too low for PHP applications.

This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.