<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[AdminsForum - Web servers]]></title>
		<link>https://adminsforum.com/</link>
		<description><![CDATA[AdminsForum - https://adminsforum.com]]></description>
		<pubDate>Thu, 15 Oct 2026 06:08:10 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[How to Fix Nginx 502 Bad Gateway — Complete Troubleshooting Guide]]></title>
			<link>https://adminsforum.com/Thread-guide-how-to-fix-nginx-502-bad-gateway-%E2%80%94-complete-troubleshooting-guide</link>
			<pubDate>Thu, 08 Oct 2026 01:51:02 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-how-to-fix-nginx-502-bad-gateway-%E2%80%94-complete-troubleshooting-guide</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">A 502 Bad Gateway means a gateway did not receive a usable response from its upstream. Fix the failed link in the request path rather than repeatedly restarting the whole server.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Scope:</span> This guide covers Nginx in front of PHP-FPM or an HTTP application on Linux. Commands assume a conventional systemd installation. Panel-managed Nginx may have different binaries, paths and service names; use the panel's supported configuration tools and logs. Back up the affected configuration before editing. Never share unredacted nginx -T output: configuration can contain secrets.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1. Identify which layer returns the error</span></span><br />
Write down the failing URL, time, request method and whether all pages fail or only one application. A CDN, load balancer, Nginx or the application itself can return 502. Response branding and headers are clues, not proof. Correlate the same request with each layer's logs.<br />
<br />
For a harmless public endpoint:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -sS -D - -o /dev/null https://example.com/health</code></div></div>Use a real, safe URL; do not replay payments or other state-changing requests. If authorized to test the origin directly, preserve the hostname and TLS validation:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl --resolve example.com:443:YOUR_ORIGIN_IP -sS -D - -o /dev/null https://example.com/health</code></div></div>Do not add -k to hide a certificate problem. An origin restricted to the CDN may correctly reject your workstation.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2. Read the matching error log</span></span><br />
Find the error_log directive for the affected virtual host. /var/log/nginx/error.log is a common package default, not a universal path:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u nginx --since "15 minutes ago" --no-pager
sudo nginx -t</code></div></div>Inspect nginx -T locally if you need to locate the active server block, proxy_pass or fastcgi_pass. Ensure you are using the binary/configuration that the running service actually uses. Note the upstream address and exact error.<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Connection refused:</span> The target port/socket has no accepting service, or a device actively rejects it. Check process health and listener address.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">No such file or directory:</span> A Unix socket path is wrong or the expected socket was never created.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Permission denied:</span> Check socket and parent-directory access plus SELinux/AppArmor denials.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream prematurely closed connection:</span> Investigate application crashes, worker termination and backend logs.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream sent invalid header / too big header:</span> Inspect backend output, cookies and response headers. Protocol mismatch or oversized headers needs a specific fix.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream timed out:</span> Investigate slow or overloaded dependencies. This often produces 504; error-page mappings and intermediate gateways can change the displayed status.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3. Check backend health and capacity</span></span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo ss -lntp
sudo ss -lxnp
systemctl --failed
free -h
df -h
df -i
sudo journalctl -k --since "30 minutes ago" --no-pager</code></div></div>Look for an OOM kill, exhausted disk/inodes, a crash loop or a deployment at the same timestamp. Confirm the backend's service name before inspecting its status and journal. Restart only the affected service after capturing evidence and understanding the impact; repeated restarts can hide the cause and interrupt healthy requests.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4. PHP-FPM: make the listener and fastcgi_pass agree</span></span><br />
A PHP version change commonly leaves Nginx pointing at an old socket. Discover your installed FPM units instead of assuming a PHP version:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>systemctl list-units --all --type=service 'php*-fpm.service'
ls -l /run/php/</code></div></div>Inspect the selected FPM pool's listen setting and the site's fastcgi_pass. These are alternative examples, not values to paste blindly:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code># Unix socket example
fastcgi_pass unix:/run/php/php8.3-fpm.sock;

# TCP listener example
fastcgi_pass 127.0.0.1:9000;</code></div></div>Use the actual path/address, and keep FPM on a private interface. Port 9000 is FastCGI, not HTTP: curl to it is not a valid application health check. Verify that the Nginx worker identity can traverse the socket's parent directories and access the socket. Correct FPM listen.owner, listen.group and listen.mode as appropriate for your deployment; a manual chmod may disappear when FPM recreates the socket.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Do not use chmod 777 or disable SELinux/AppArmor.</span> If discretionary permissions look correct, inspect security-policy denials. If FPM logs show pm.max_children saturation, measure worker memory and request duration before changing limits. More workers can trigger OOM on a small VPS. Also inspect database latency and slow requests.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5. HTTP applications: test the configured endpoint locally</span></span><br />
For an application intentionally listening on loopback TCP 3000:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl --max-time 10 -sS -D - -o /dev/null http://127.0.0.1:3000/health</code></div></div>Replace the port/path with the real endpoint. If it requires a Host header, include the expected hostname. If this fails, fix the backend before editing Nginx. If it succeeds, compare the endpoint with proxy_pass and check whether the backend expects HTTP or HTTPS. Preserve certificate validation and configure upstream SNI/trust correctly for HTTPS.<br />
<br />
Inside a container, 127.0.0.1 means that container, not another container or the host. Verify service DNS names, networks and listeners from the Nginx container's context. Avoid publishing an internal application port to the Internet as a troubleshooting shortcut.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">6. Check changes and limits without guesswork</span></span><br />
If the backend is reachable but only large/login responses fail, inspect the exact header/buffer error and backend response. Fix oversized cookies or abnormal headers first. Change proxy/FastCGI buffer directives only for the relevant site with a measured requirement.<br />
<br />
If requests are slow, inspect application, database and external API timing before raising proxy_read_timeout or fastcgi_read_timeout. Those read timeouts concern inactivity between reads, not a universal total-request deadline. Raising them cannot repair a dead listener and may keep scarce workers occupied longer. Prefer background jobs for long-running work.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">7. Apply one fix and verify it</span></span><br />
After a backed-up configuration edit:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo nginx -t</code></div></div>Only if the test succeeds, reload using the deployment's supported mechanism. On a conventional package installation:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo systemctl reload nginx</code></div></div>Test the affected endpoint and a normal page again, check the logs for fresh errors and watch the backend under realistic traffic. A successful syntax check does not prove the upstream works. If the change fails, restore the saved configuration, validate it and reload. On panels, keep persistent changes in the supported template/settings so regeneration does not overwrite them.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">When asking for help, include:</span> OS, panel/container details, Nginx/PHP/app versions, the relevant redacted error line, whether static/PHP/all routes fail, the configured upstream type and the last change before failure. Remove tokens, private keys, credentials and user data from logs/configuration.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Official references</span><ul class="mycode_list"><li><a href="https://nginx.org/en/docs/beginners_guide.html" target="_blank" rel="noopener" class="mycode_url">Nginx beginner's guide and configuration testing</a><br />
</li>
<li><a href="https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy" target="_blank" rel="noopener" class="mycode_url">Nginx reverse proxy documentation</a><br />
</li>
<li><a href="https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html" target="_blank" rel="noopener" class="mycode_url">Nginx FastCGI module directives</a><br />
</li>
</ul>
]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">A 502 Bad Gateway means a gateway did not receive a usable response from its upstream. Fix the failed link in the request path rather than repeatedly restarting the whole server.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Scope:</span> This guide covers Nginx in front of PHP-FPM or an HTTP application on Linux. Commands assume a conventional systemd installation. Panel-managed Nginx may have different binaries, paths and service names; use the panel's supported configuration tools and logs. Back up the affected configuration before editing. Never share unredacted nginx -T output: configuration can contain secrets.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">1. Identify which layer returns the error</span></span><br />
Write down the failing URL, time, request method and whether all pages fail or only one application. A CDN, load balancer, Nginx or the application itself can return 502. Response branding and headers are clues, not proof. Correlate the same request with each layer's logs.<br />
<br />
For a harmless public endpoint:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -sS -D - -o /dev/null https://example.com/health</code></div></div>Use a real, safe URL; do not replay payments or other state-changing requests. If authorized to test the origin directly, preserve the hostname and TLS validation:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl --resolve example.com:443:YOUR_ORIGIN_IP -sS -D - -o /dev/null https://example.com/health</code></div></div>Do not add -k to hide a certificate problem. An origin restricted to the CDN may correctly reject your workstation.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">2. Read the matching error log</span></span><br />
Find the error_log directive for the affected virtual host. /var/log/nginx/error.log is a common package default, not a universal path:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u nginx --since "15 minutes ago" --no-pager
sudo nginx -t</code></div></div>Inspect nginx -T locally if you need to locate the active server block, proxy_pass or fastcgi_pass. Ensure you are using the binary/configuration that the running service actually uses. Note the upstream address and exact error.<br />
<ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Connection refused:</span> The target port/socket has no accepting service, or a device actively rejects it. Check process health and listener address.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">No such file or directory:</span> A Unix socket path is wrong or the expected socket was never created.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Permission denied:</span> Check socket and parent-directory access plus SELinux/AppArmor denials.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream prematurely closed connection:</span> Investigate application crashes, worker termination and backend logs.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream sent invalid header / too big header:</span> Inspect backend output, cookies and response headers. Protocol mismatch or oversized headers needs a specific fix.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Upstream timed out:</span> Investigate slow or overloaded dependencies. This often produces 504; error-page mappings and intermediate gateways can change the displayed status.<br />
</li>
</ul>
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">3. Check backend health and capacity</span></span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo ss -lntp
sudo ss -lxnp
systemctl --failed
free -h
df -h
df -i
sudo journalctl -k --since "30 minutes ago" --no-pager</code></div></div>Look for an OOM kill, exhausted disk/inodes, a crash loop or a deployment at the same timestamp. Confirm the backend's service name before inspecting its status and journal. Restart only the affected service after capturing evidence and understanding the impact; repeated restarts can hide the cause and interrupt healthy requests.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">4. PHP-FPM: make the listener and fastcgi_pass agree</span></span><br />
A PHP version change commonly leaves Nginx pointing at an old socket. Discover your installed FPM units instead of assuming a PHP version:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>systemctl list-units --all --type=service 'php*-fpm.service'
ls -l /run/php/</code></div></div>Inspect the selected FPM pool's listen setting and the site's fastcgi_pass. These are alternative examples, not values to paste blindly:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code># Unix socket example
fastcgi_pass unix:/run/php/php8.3-fpm.sock;

# TCP listener example
fastcgi_pass 127.0.0.1:9000;</code></div></div>Use the actual path/address, and keep FPM on a private interface. Port 9000 is FastCGI, not HTTP: curl to it is not a valid application health check. Verify that the Nginx worker identity can traverse the socket's parent directories and access the socket. Correct FPM listen.owner, listen.group and listen.mode as appropriate for your deployment; a manual chmod may disappear when FPM recreates the socket.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Do not use chmod 777 or disable SELinux/AppArmor.</span> If discretionary permissions look correct, inspect security-policy denials. If FPM logs show pm.max_children saturation, measure worker memory and request duration before changing limits. More workers can trigger OOM on a small VPS. Also inspect database latency and slow requests.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5. HTTP applications: test the configured endpoint locally</span></span><br />
For an application intentionally listening on loopback TCP 3000:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl --max-time 10 -sS -D - -o /dev/null http://127.0.0.1:3000/health</code></div></div>Replace the port/path with the real endpoint. If it requires a Host header, include the expected hostname. If this fails, fix the backend before editing Nginx. If it succeeds, compare the endpoint with proxy_pass and check whether the backend expects HTTP or HTTPS. Preserve certificate validation and configure upstream SNI/trust correctly for HTTPS.<br />
<br />
Inside a container, 127.0.0.1 means that container, not another container or the host. Verify service DNS names, networks and listeners from the Nginx container's context. Avoid publishing an internal application port to the Internet as a troubleshooting shortcut.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">6. Check changes and limits without guesswork</span></span><br />
If the backend is reachable but only large/login responses fail, inspect the exact header/buffer error and backend response. Fix oversized cookies or abnormal headers first. Change proxy/FastCGI buffer directives only for the relevant site with a measured requirement.<br />
<br />
If requests are slow, inspect application, database and external API timing before raising proxy_read_timeout or fastcgi_read_timeout. Those read timeouts concern inactivity between reads, not a universal total-request deadline. Raising them cannot repair a dead listener and may keep scarce workers occupied longer. Prefer background jobs for long-running work.<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">7. Apply one fix and verify it</span></span><br />
After a backed-up configuration edit:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo nginx -t</code></div></div>Only if the test succeeds, reload using the deployment's supported mechanism. On a conventional package installation:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo systemctl reload nginx</code></div></div>Test the affected endpoint and a normal page again, check the logs for fresh errors and watch the backend under realistic traffic. A successful syntax check does not prove the upstream works. If the change fails, restore the saved configuration, validate it and reload. On panels, keep persistent changes in the supported template/settings so regeneration does not overwrite them.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">When asking for help, include:</span> OS, panel/container details, Nginx/PHP/app versions, the relevant redacted error line, whether static/PHP/all routes fail, the configured upstream type and the last change before failure. Remove tokens, private keys, credentials and user data from logs/configuration.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Official references</span><ul class="mycode_list"><li><a href="https://nginx.org/en/docs/beginners_guide.html" target="_blank" rel="noopener" class="mycode_url">Nginx beginner's guide and configuration testing</a><br />
</li>
<li><a href="https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy" target="_blank" rel="noopener" class="mycode_url">Nginx reverse proxy documentation</a><br />
</li>
<li><a href="https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html" target="_blank" rel="noopener" class="mycode_url">Nginx FastCGI module directives</a><br />
</li>
</ul>
]]></content:encoded>
		</item>
	</channel>
</rss>