How to Fix 502 Bad Gateway in nginx on Ubuntu
A 502 Bad Gateway page with nginx/1.18.0 (Ubuntu), nginx/1.24.0 or a newer version underneath means nginx is working but could not get a valid answer from the service behind it. That is usually PHP-FPM for WordPress and other PHP sites, or a Node.js or Python app. Visitors see a blank error, forms stop working, and if it lasts, search engines slow down crawling. The version number rarely matters; the cause is almost always a stopped service, a wrong socket or port, a permissions problem, a crash or a header that is too big. This guide shows you how to read the nginx error log, match the message to its cause, apply the exact configuration fix on Ubuntu, and make sure it does not come back after the next upgrade or reboot.
What 502 Bad Gateway from nginx means
nginx is very often a reverse proxy: it accepts the visitor's request and passes it to something else that builds the page, such as PHP-FPM for WordPress, a Node.js app, a Python app server, or Apache on a Plesk server. A 502 Bad Gateway means nginx tried to hand the request over and got no valid response back. nginx itself is running fine, which is why it can show you the error page at all. The problem is the thing behind it, or the connection between the two.
The line under the heading, such as nginx/1.18.0 (Ubuntu), nginx/1.24.0 (Ubuntu), nginx/1.29.1 or nginx/1.30.2, only tells you which nginx build is installed. Ubuntu 20.04 and 22.04 ship 1.18.0, Ubuntu 24.04 ships 1.24.0, and higher numbers usually come from the nginx.org packages. The causes and fixes for a 502 are the same on all of them, so you do not need to upgrade nginx to fix it.
| Status | What nginx is telling you | Usual direction to look |
|---|---|---|
| 502 Bad Gateway | The upstream refused the connection, closed it early or sent something invalid | Is the app or PHP-FPM running, and is nginx pointed at the right socket or port? |
| 504 Gateway Timeout | The upstream accepted the connection but took too long to answer | Slow code, slow database, or timeouts set too low |
| 503 Service Unavailable | Often a rate limit, maintenance mode or the app saying it is overloaded | nginx limit rules, the app's own maintenance switch |
If the error page says cloudflare instead of nginx, the 502 came from Cloudflare failing to reach your server, which is a different check. The broader 502 errors guide covers CDN and host-level causes; this page is about the nginx server itself.
Why you are getting 502 Bad Gateway in nginx
Each cause leaves a recognisable message in /var/log/nginx/error.log. Match your log line to this table and you will usually know the fix before you open a config file.
| Error log message | What it means | Fix |
|---|---|---|
connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory) | PHP-FPM is stopped, or nginx points at a socket for a different PHP version | Start PHP-FPM, or correct the socket path in fastcgi_pass |
connect() to unix:... failed (13: Permission denied) | The socket exists but the nginx user cannot open it | Set listen.owner, listen.group and listen.mode in the PHP-FPM pool |
connect() failed (111: Connection refused) while connecting to upstream | Nothing is listening on that IP address and port | Start the app, or fix the port in proxy_pass |
upstream prematurely closed connection while reading response header | The app or PHP process crashed or was killed mid-request | Check the app or PHP log for fatal errors and memory limits |
upstream sent too big header while reading response header | Headers such as large cookies are bigger than the buffer | Raise proxy_buffer_size or fastcgi_buffer_size |
recv() failed (104: Connection reset by peer) | The upstream dropped the connection, often under load | Check PHP-FPM pm.max_children and app worker limits |
no live upstreams while connecting to upstream | Every server in an upstream block has been marked as failed | Fix the backends, then check max_fails settings |
The two most common causes on Ubuntu are a PHP upgrade that changed the socket name, for example from php8.1-fpm.sock to php8.3-fpm.sock after moving to Ubuntu 24.04, and a Node.js app that stopped after a reboot because nothing was set up to restart it.
How to diagnose it on Ubuntu
Work through these commands in order. Run them over SSH as a user with sudo rights.
1. Read the error log
sudo tail -n 50 /var/log/nginx/error.log
# Watch it live while you reload the failing page
sudo tail -f /var/log/nginx/error.logIf the site has its own log file, find it with sudo grep -R error_log /etc/nginx/sites-enabled/. On Plesk, each domain has its own proxy log at /var/www/vhosts/system/example.com/logs/proxy_error_log.
2. Find out what nginx is pointing at
sudo nginx -T 2>/dev/null | grep -nE "fastcgi_pass|proxy_pass|upstream"This prints the socket path or address and port each site uses. Compare it with what is actually running.
3. Check the upstream is running
# PHP-FPM: which versions are installed and are they active?
ls /run/php/
systemctl status 'php*-fpm' --no-pager
# Node or another app on a port: is anything listening?
sudo ss -ltnp | grep -E ':3000|:8000|:8080'
# Apps run by pm2 or systemd
pm2 status
systemctl status myapp --no-pager4. Test the upstream directly
# Bypass nginx and ask the Node app for a page
curl -sI http://127.0.0.1:3000/
# Check the PHP-FPM socket permissions
ls -l /run/php/php8.3-fpm.sockIf the direct request works but the site still gives 502, the problem is in the connection between nginx and the app: a wrong path, a wrong port, permissions, or buffers. If the direct request also fails, fix the app first. The app's own logs are the next stop, for example sudo journalctl -u php8.3-fpm -n 50 or pm2 logs.
The key configuration fixes
Point nginx at the right PHP-FPM socket
# /etc/nginx/sites-available/example.com
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}The socket name must match the installed PHP version exactly. After editing, always test the config before reloading, because a syntax error stops the reload:
sudo nginx -t && sudo systemctl reload nginxFix socket permissions in the PHP-FPM pool
; /etc/php/8.3/fpm/pool.d/www.conf
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660The user directive at the top of /etc/nginx/nginx.conf is www-data on Ubuntu by default. If you changed it, the pool owner or group must match. Restart PHP-FPM with sudo systemctl restart php8.3-fpm after the change.
Give PHP-FPM enough workers
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6If the PHP-FPM log says server reached pm.max_children setting, requests are queuing. Work out a safe number by dividing the memory you can spare for PHP by the average size of one PHP process, which you can see with ps -o rss= -C php-fpm8.3. Setting it too high makes the server run out of memory, and the out-of-memory killer then causes more 502s.
Proxy a Node.js app correctly
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
}Use 127.0.0.1 rather than localhost. On some systems localhost resolves to the IPv6 address ::1 first, and an app listening only on IPv4 then refuses the connection. The buffer lines fix the too big header message; for PHP the equivalents are fastcgi_buffer_size 32k; and fastcgi_buffers 16 16k;.
proxy_read_timeout does not fix a 502. Timeouts produce 504 errors. If you get a 502, the upstream is refusing or dropping the connection, so look at whether it is running and reachable.Platform notes
- WordPress on Ubuntu. A 502 after a plugin update is usually a PHP fatal error or memory exhaustion that kills the worker. Check
/var/log/php8.3-fpm.logand the site's PHP error log, and disable the plugin by renaming its folder inwp-content/plugins. See HTTP errors in WordPress. - Node.js apps. Run the app under pm2 or a systemd service so it restarts after a crash or a reboot. With pm2,
pm2 startupfollowed bypm2 savesets this up. See HTTP errors in Node.js. - Plesk. nginx usually sits in front of Apache or PHP-FPM handlers that Plesk manages. Check the domain's
proxy_error_log, then use Repair in Tools and Settings orplesk repair web example.comto rebuild configuration files. See HTTP errors in Plesk. - Docker. Inside a container,
127.0.0.1means the container itself. Use the service name from your compose file, such asproxy_pass http://app:3000;, and make sure both containers share a network.
A worked example
Example Bakery upgrades its server from Ubuntu 22.04 to 24.04. After the reboot, every page shows 502 Bad Gateway with nginx/1.24.0 (Ubuntu) underneath. The home page is cached as static HTML and still loads, which is confusing at first.
The error log has one line repeated for every request:
2026/10/14 08:12:31 [crit] 1184#1184: *42 connect() to unix:/run/php/php8.1-fpm.sock failed
(2: No such file or directory) while connecting to upstream, client: 203.0.113.25,
server: www.example.com, request: "GET /order/ HTTP/2.0",
upstream: "fastcgi://unix:/run/php/php8.1-fpm.sock:", host: "www.example.com"Running ls /run/php/ shows only php8.3-fpm.sock. The upgrade replaced PHP 8.1 with 8.3, but the site config still names the old socket. The administrator changes fastcgi_pass to unix:/run/php/php8.3-fpm.sock, runs sudo nginx -t, reloads nginx and requests the order page with curl. It returns HTTP/2 200.
A day later, a few 502s appear at lunchtime. This time the log says upstream prematurely closed connection, and the PHP-FPM log shows server reached pm.max_children setting (5). Each PHP process uses about 80 MB and the server has about 2 GB to spare, so pm.max_children is raised to 20. The lunchtime 502s stop.
The fix, step by step
Step 1
Read the nginx error log
Connect over SSH and run sudo tail -n 50 /var/log/nginx/error.log, then reload the failing page while sudo tail -f is running so you see the exact line it writes. Copy the message, the upstream address and the request path. The message tells you which of the common causes you are dealing with, so match it against the causes table before changing any configuration, and keep the line for comparison after the fix.
Step 2
Find the configured upstream
Run sudo nginx -T 2>/dev/null | grep -nE "fastcgi_pass|proxy_pass" to list every socket path and address the sites use. Note the one for the failing site. If the site has an upstream block, read the servers listed in it too. You now know what nginx is trying to reach, which you will compare with what is actually running on the server in the next step of the fix.
Step 3
Check the upstream is running
For PHP sites, run ls /run/php/ and systemctl status 'php*-fpm' to see which versions exist and whether they are active. For Node or other apps, run sudo ss -ltnp and look for the port, then check pm2 status or the systemd service. Start anything that is stopped with sudo systemctl start or pm2 start, and read its own log if it stops again straight away.
Step 4
Correct the socket path or port
If the configured socket or port does not match what is running, edit the site file in /etc/nginx/sites-available/ so fastcgi_pass names the real socket, such as unix:/run/php/php8.3-fpm.sock, or proxy_pass uses the real port on 127.0.0.1. Save the file, run sudo nginx -t to check the syntax, then sudo systemctl reload nginx. Request the page with curl and look for a 200 status.
Step 5
Fix socket permissions
If the log shows Permission denied, open the PHP-FPM pool file, usually /etc/php/8.3/fpm/pool.d/www.conf, and set listen.owner and listen.group to the user nginx runs as, which is www-data on Ubuntu, with listen.mode = 0660. Restart PHP-FPM with sudo systemctl restart php8.3-fpm, check the socket owner with ls -l /run/php/, and reload the page to confirm the error has gone. If the nginx user was changed from the default, use that user in the pool settings instead.
Step 6
Stop the upstream crashing
If the log shows the connection closed early or was reset, read the application or PHP-FPM log for fatal errors, memory limits or pm.max_children warnings. Fix the code error, raise memory_limit if a single request needs more, or raise pm.max_children to a number your memory can support. Check sudo dmesg for out-of-memory kills. Load the page several times and watch the error log stay quiet.
Step 7
Raise buffers for large headers
If the log says upstream sent too big header, add proxy_buffer_size 16k;, proxy_buffers 8 16k; and proxy_busy_buffers_size 32k; to the location that proxies the app, or fastcgi_buffer_size 32k; and fastcgi_buffers 16 16k; for PHP. Test with sudo nginx -t, reload, then repeat the request that failed, often a logged-in page or one that sets several cookies, and confirm it returns 200.
Step 8
Verify and make it last
Request several dynamic pages with curl -sI and confirm they return 200, then reboot the server in a quiet period and check the upstream starts again by itself. Enable PHP-FPM with sudo systemctl enable, or run pm2 startup and pm2 save for Node apps. Finally, crawl the site from outside and check the error log stays free of new connect() failed lines over the following day of normal traffic.
Edge cases worth knowing
- Only some pages fail. Static files are served by nginx directly, so they keep working while anything handled by PHP or the app gives 502. A mix like this points straight at the upstream.
- 502 only on large pages or after login. This often matches the too big header message, caused by large cookies or many
Set-Cookieheaders. Raise the buffer sizes. - Intermittent 502 under load. Look for
pm.max_childrenwarnings, the out-of-memory killer insudo dmesg | grep -i kill, or an app that restarts often inpm2 status. - HTTPS upstreams. If
proxy_passuseshttps://, a certificate or SNI problem can cause 502s. Addproxy_ssl_server_name on;when the upstream needs the host name. - Search engines. A short burst of 502s does no lasting harm, but long or repeated outages slow Google's crawling. See Server error (5xx) in Search Console.
- Timeouts that look like 502s. If the log says
upstream timed out, you are dealing with a 504. The 504 errors guide covers that.
Keeping 502s away
- Always run
sudo nginx -tbefore reloading, and keep a copy of working configs before upgrades. - After any PHP or Ubuntu upgrade, run
ls /run/php/andsudo nginx -T | grep fastcgi_passto check they still agree. - Make every upstream restart on its own: systemd services with
Restart=always, or pm2 withpm2 startupandpm2 save. - Set up a simple uptime check that requests a PHP or app page, not a static file, every minute.
- Rotate and watch
/var/log/nginx/error.log; a sudden rise inconnect() failedlines is an early warning. - Re-crawl the site after changes and look for any 5xx responses. The HTTP error audit guide explains how to read the results.
1. Why am I getting 502 Bad Gateway from nginx?
You are getting a 502 because nginx passed the request to an upstream service, such as PHP-FPM or a Node.js app, and got no valid response. The upstream may be stopped, nginx may be pointing at the wrong socket or port, the nginx user may lack permission to open the socket, or the upstream may have crashed mid-request. The nginx error log, usually at /var/log/nginx/error.log, records the exact reason for each failed request, so read it first.
2. How do I fix 502 Bad Gateway nginx/1.18.0 (Ubuntu)?
Fix it the same way as on any nginx version: read the error log, then start or reconnect the upstream it names. nginx 1.18.0 is the version shipped with Ubuntu 20.04 and 22.04, and upgrading it rarely helps. On those systems the usual causes are PHP-FPM not running, a socket path for the wrong PHP version, or a Node app that stopped. Run sudo tail on the error log, compare the socket or port it names with what is running, and correct the config.
3. How do I fix 502 Bad Gateway nginx 1.24.0 on Ubuntu 24.04?
Check whether your nginx config still points at an old PHP socket, because that is the most common cause after moving to Ubuntu 24.04. That release ships nginx 1.24.0 and PHP 8.3, so a site set up for PHP 8.1 or 7.4 asks for a socket that no longer exists. Run ls /run/php to see the real socket name, update fastcgi_pass to match, test with sudo nginx -t and reload nginx. Other causes are the same as on any version.
4. Does upgrading nginx to 1.29 or 1.30 fix a 502?
No, a newer nginx such as 1.29.1 or 1.30.2 will not fix a 502 on its own, because the error is about the service behind nginx, not nginx itself. Those version numbers usually come from the official nginx.org packages, and they show the same 502 page when an upstream is down or misconfigured. Read the error log on that server, check that PHP-FPM or the app is running and reachable, and fix the socket, port, permissions or buffer settings it points to.
5. What is the difference between a 502 and a 504 in nginx?
A 502 means the upstream refused, dropped or garbled the connection, while a 504 means it accepted the connection but did not answer in time. They need different fixes. A 502 points at a service that is stopped, unreachable or crashing, so you check it is running and that nginx is pointed at it correctly. A 504 points at slow code, slow database queries or timeouts set too low, so you look at performance and settings such as proxy_read_timeout.
6. Can a 502 Bad Gateway hurt my SEO?
A short 502 outage does little harm, but repeated or long ones can reduce how often Google crawls your site and eventually drop pages from results. Google treats 5xx responses as a temporary server problem and retries the URL later. If the errors continue for days, it slows crawling to protect your server and may remove URLs it cannot fetch. Fix the cause quickly, then check the Pages and Crawl stats reports in Search Console to confirm Google is fetching pages normally again.
7. How do I check if PHP-FPM is running?
Run systemctl status php8.3-fpm, replacing 8.3 with your PHP version, and look for active (running) in the output. If you are not sure which version is installed, ls /run/php lists the sockets that exist, and systemctl list-units with a php filter lists the services. If it is stopped, start it with sudo systemctl start, and enable it with sudo systemctl enable so it starts after a reboot. If it fails to start, sudo journalctl for that unit shows the reason.
Our HTTP error audit requests your pages from outside your server and lists every URL returning a 502 or other server error, so you can confirm the fix covers the whole site.
Open HTTP Error Fixes โ