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 upstreamAnalysis
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
5Step 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 exitStep 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 workersStep 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
1024Solution
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-fpmFix 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 nginxFix 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.confFix 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 nginxFix 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
doneQuick 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 -lLessons Learned
- 502 Bad Gateway means upstream failure - always check the upstream server first.
- PHP-FPM worker exhaustion is the most common cause - increase
pm.max_children. - Monitor worker count in production to catch exhaustion before it causes errors.
- Unix sockets are faster but TCP sockets are easier to debug.
- 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.