How to Troubleshoot and Fix 502 Bad Gateway Errors
A 502 Bad Gateway error indicates that an edge server (such as a reverse proxy, load balancer, or CDN) received an invalid, malformed, or missing response from the upstream origin server handling the request.
Architecture Overview
In modern web infrastructure, client requests pass through multiple layers:
Client Browser ──▶ CDN / Edge (e.g., Cloudflare) ──▶ Reverse Proxy (e.g., Nginx) ──▶ Upstream Daemon (PHP-FPM, Node.js, Python/Gunicorn)
▲
[Failure point triggers 502]
When the reverse proxy cannot establish a stable socket connection, receives an unexpected termination signal, or gets an empty/invalid payload from the backend upstream service, it returns an HTTP 502 response to the client.
Quick Diagnosis: Visitor vs. Site Administrator
| Role | Primary Suspect | Action Item |
|---|---|---|
| Site Visitor | Stale local cache, corrupted DNS resolution, or local network proxy. | Perform a hard refresh, test via Incognito, switch DNS. |
| Site Owner / Sysadmin | Down backend service, process pool exhaustion, timeout mismatch, or firewall blocks. | Inspect service status, check error logs, tune proxy timeouts. |
Troubleshooting for Visitors and End Users
- Force a Cache Reload: Force your browser to bypass cached resources:
- Windows/Linux: Press
Ctrl+F5orCtrl+Shift+R. - macOS: Press
Cmd+Shift+R.
- Windows/Linux: Press
- Test in Private/Incognito Mode: Confirms whether browser extensions (e.g., ad blockers, VPN extensions) or cookie corruptions are interfering with the gateway handshake.
- Flush Local DNS Cache:
# Windows (Command Prompt) ipconfig /flushdns # macOS (Terminal) sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder # Linux (systemd-resolved) sudo resolvectl flush-caches
Troubleshooting for Website Owners & DevOps
1. Verify Upstream Application Status
Ensure the actual backend application or application server is active and listening on its designated port or UNIX socket:
# For PHP-FPM
sudo systemctl status php-fpm # (or php8.2-fpm, php8.3-fpm)
# For Node.js / PM2
pm2 status
# For Python (Gunicorn/Uvicorn)
sudo systemctl status gunicorn
# Verify the port/socket is listening
sudo ss -tulpn | grep -E ':(80|443|3000|8000|9000)'
If the service has stopped or crashed, restart it:
sudo systemctl restart php-fpm
sudo systemctl restart nginx
2. Inspect Web Server and Upstream Error Logs
The logs contain the exact failure mode (e.g., Connection refused, Connection timed out, or Premature end of script headers):
# Nginx Error Log
sudo tail -n 50 -f /var/log/nginx/error.log
# Apache Error Log
sudo tail -n 50 -f /var/log/apache2/error.log # Debian/Ubuntu
sudo tail -n 50 -f /var/log/httpd/error_log # RHEL/CentOS
# Check system kernel messages for OOM (Out of Memory) kills
sudo dmesg -T | grep -i -E 'oom|killed process'
3. Fix Timeout and Buffer Limits
If complex queries or file uploads take longer to compute than your proxy allows, the proxy severs the connection prematurely and returns a 502.
For Nginx as a Reverse Proxy, adjust the proxy timeout thresholds in your nginx.conf or site block (/etc/nginx/sites-available/):
location / {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 60s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
For Nginx with PHP-FPM, increase the FastCGI execution buffers and timeouts:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_read_timeout 120s;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
Remember to test configuration syntax before reloading:
sudo nginx -t && sudo systemctl reload nginx
4. Inspect PHP-FPM Process Pool Saturation
If all workers are occupied, incoming requests queue up and eventually fail with a gateway timeout or drop. Open your pool configuration (e.g., /etc/php/8.x/fpm/pool.d/www.conf) and adjust worker allocations based on available RAM:
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
5. Check Edge Firewall & Cloudflare Configuration
- Standard 502 Screen (Cloudflare Branded): Cloudflare reached your origin web server, but your server returned a native 502 response back to Cloudflare. Focus debugging on your origin host.
- Error 502 / 504 with "Host Error": Cloudflare could not complete the TCP connection to your origin IP or the connection was dropped by a hosting-level firewall (e.g.,
iptables, UFW, AWS Security Group). Ensure Cloudflare IPs are whitelisted on your origin.
Prevention & Monitoring Recommendations
- Health Checks: Configure automated external uptime checks targeting an un-cached
/healthzendpoint. - Memory Alerts: Configure swap and system memory alerting via Prometheus/Grafana or Datadog to detect OOM events before PHP/Node workers die.
- Graceful Restarts: Always use
reloadinstead ofrestartduring deployments (e.g.,nginx -s reload,pm2 reload) to avoid dropping in-flight socket connections.