TudCloud Inc.Journal
← Back to the journal

Operations

How to Troubleshoot Nginx 502 Bad Gateway on a VPS

TudCloud Editorial · September 27, 2026 · 4 min read

Three server nodes with a broken backend connection and an amber diagnostic warning.

A 502 Bad Gateway response usually means a proxy could not obtain a valid response from its upstream service. Restarting everything may briefly hide the symptom while erasing useful evidence. Follow the request path instead: browser, any CDN, Nginx, then the application or PHP-FPM worker.

Before you begin: these examples assume a Linux server using systemd and Nginx. Replace the example hostname, application unit, port, and PHP-FPM socket with your actual values. Commands are diagnostic unless explicitly marked as a configuration change.

1. Identify which layer produced the error

curl -sS -D - -o /dev/null https://app.example.com/
sudo tail -n 80 /var/log/nginx/error.log
sudo journalctl -u nginx --since "15 minutes ago" --no-pager

Record the failing URL and timestamp, then match them to your logs. Headers and branded error pages are clues, not proof: a CDN can relay an origin error. If your origin serves HTTPS locally, compare it with the public path from the server:

curl --resolve app.example.com:443:127.0.0.1 \
  -sS -D - -o /dev/null https://app.example.com/

This preserves the hostname for TLS and HTTP while bypassing public DNS. Use the actual bound origin address if it is not listening on loopback. Do not add -k to conceal certificate errors. A healthy local response and a failing public response move the investigation toward CDN-to-origin connectivity, TLS configuration, or routing.

2. Read the upstream error literally

  • Connection refused: verify the upstream process is listening on the configured address and port.
  • No such file or directory: a Unix socket path may be wrong or the worker may not have created it.
  • Permission denied: inspect socket and directory access and, where enabled, SELinux policy.
  • Prematurely closed connection: inspect application crashes, worker exits, and memory pressure.
  • Upstream timed out: inspect slow requests and dependencies; this often produces 504 rather than 502.

Use the exact message and request timestamp to narrow the next check. Do not treat every gateway error as a reason to increase all timeouts.

3. Test an HTTP application directly

sudo ss -ltnp
sudo systemctl status myapp --no-pager
sudo journalctl -u myapp --since "15 minutes ago" --no-pager
curl -sS -D - -o /dev/null -H "Host: app.example.com" http://127.0.0.1:3000/

If direct access fails too, repair the application before changing Nginx. Check whether a deployment changed the port or bind address. For containers, loopback refers to the current network namespace; Nginx in another container cannot reach an app through its own 127.0.0.1. Keep a local-only application listener private instead of opening its port publicly as a workaround.

A minimal HTTP upstream location might look like this:

location / {
    proxy_pass http://127.0.0.1:3000;
    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;
}

This is a location block inside an existing server block, not a complete site configuration. Match it to the application’s actual listener. Configure the application to trust forwarding headers only from known proxies. When using subpaths, remember that adding a URI to proxy_pass changes URI replacement behavior; review the Nginx proxy module reference.

4. For PHP sites, verify PHP-FPM instead

sudo ss -lxnp
sudo systemctl status php-fpm --no-pager
sudo journalctl -u php-fpm --since "15 minutes ago" --no-pager
sudo nginx -T

Debian and Ubuntu often use a versioned service such as php8.3-fpm; discover the installed unit rather than assuming that name. Compare Nginx’s fastcgi_pass with the FPM pool’s listen value. Inspect socket ownership, mode, and access to parent directories. Do not use chmod 777. On SELinux systems, check recent AVC denials and fix the relevant label or policy instead of disabling enforcement. The nginx -T output can contain sensitive configuration: redact it before sharing.

5. Check resource pressure before changing capacity

free -h
df -h
sudo journalctl -k --since "30 minutes ago" --no-pager

Look for out-of-memory kills near the failure, a full filesystem, or worker-limit messages in the application logs. Increasing PHP-FPM workers on a small VPS can make memory exhaustion worse. Estimate memory per worker and leave headroom for the operating system, database, and other services. If disk usage is the issue, use our Linux disk troubleshooting guide.

6. Validate the fix and keep a rollback path

sudo nginx -t && sudo systemctl reload nginx

Save the previous configuration before editing. The -t check validates syntax and referenced files; it does not prove that the upstream is healthy. See Nginx command-line parameters. After reloading, repeat the exact failing request through both the origin and public path, test a normal application action, and watch for new upstream errors. Record the root cause and the change that resolved it so the next incident starts with evidence.

Build your next project with TudCloud.Explore our servers ↗