Nginx 502 Bad Gateway with Node.js: An Inside-Out Checklist
Find the cause of an Nginx 502 after deploying Next.js, NestJS, or Node.js with curl, ss, systemd, PM2, Docker Compose, and logs.
Article by Phạm Minh Thiện
Front-end developer working directly with Next.js, NestJS, Docker, Nginx, and Ubuntu VPS deployments.
Reviewed on 7/19/2026.
Table of contents
An Nginx 502 Bad Gateway means the proxy could not obtain a valid response from its upstream. The browser only shows the final symptom; inspect the request path from Nginx to the Node.js process.
1. Read Nginx’s error log
sudo tail -n 200 /var/log/nginx/error.log
sudo nginx -t
sudo systemctl status nginx
Messages such as connect() failed (111: Connection refused) usually mean nothing is listening at the configured upstream. A timeout points to a hung process, wrong network path, or firewall rule.
2. Test the upstream directly
If Nginx uses port 3000, test it on the VPS:
curl -i http://127.0.0.1:3000/health
sudo ss -ltnp | grep :3000
If this fails, fix Node.js or its container before changing Nginx. If it succeeds, compare the address, port, path, and protocol with proxy_pass.
3. Check PM2 or systemd
pm2 status
pm2 logs myapp --lines 200
systemctl status myapp
journalctl -u myapp --since "30 minutes ago"
Look for a missing environment variable, a failed database connection, an unsupported Node version, a build that never completed, or a process that exits immediately.
4. Check Docker Compose
docker compose ps
docker compose logs --tail=200 api
docker compose exec api wget --spider --quiet http://127.0.0.1:3000/health
When Nginx runs on the host, 127.0.0.1:3000 must be published by the API container. When Nginx runs in Compose, use the service name, such as api:3000, instead of localhost.
A minimal proxy block
server {
listen 80;
server_name example.com;
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;
}
}
After editing:
sudo nginx -t
sudo systemctl reload nginx
Common causes
- PM2 or the container is stopped or restarting.
- The application listens on a different port.
- The application binds only to an unexpected interface.
- Nginx uses
localhostbut the upstream is in another container. - The app crashed while connecting to PostgreSQL or Redis.
- A firewall or provider network rule blocks the upstream path.
- The Nginx configuration was edited but not reloaded.
Five-minute checklist
- Read the Nginx error log.
- Run
nginx -t. - Check the process or container status.
- Curl the upstream directly.
- Compare
proxy_passwith the actual listener. - Check application logs and environment variables.
- Reload Nginx only after the configuration validates.
A 502 is usually resolved faster by proving each hop independently than by repeatedly refreshing the public page.
Continue reading
Related articles
Install Free HTTPS with Certbot and Nginx on Ubuntu
Install a free Let's Encrypt certificate with Certbot and Nginx on Ubuntu, verify DNS and firewall access, renew automatically, and fix ACME challenge errors.
Read article →Nginx Reverse Proxy for Node.js Applications
Configure an Nginx server block for Node.js, Next.js, or NestJS with forwarded headers, WebSockets, HTTPS, timeouts, and safe reloads.
Read article →Deploy Node.js to a VPS with PM2 and Nginx from A to Z
A practical Node.js deployment guide for Ubuntu using PM2 and Nginx, including builds, environment variables, HTTPS, logs, health checks, and rollback.
Read article →