One thing I am learning as I continue my DevOps journey is that deploying an application successfully is only part of the job. Understanding what happens when that application fails is equally important.

In this hands-on lab, I deliberately broke my Node.js backend on an AWS EC2 Ubuntu server to see how NGINX behaves. The result was the classic 502 Bad Gateway.

I documented the full lab with screenshots on my blog:
Full tutorial here → https://blog.sirvickcloud9.online/2026/10/how-i-fixed-nginx-502-bad-gateway-error.html

What I Used

  • AWS EC2 Ubuntu 22.04
  • Node.js backend on port 3000
  • NGINX 1.24.0 as reverse proxy (port 80 → 127.0.0.1:3000)

Request flow: Browser → NGINX → Node.js

What Happened

I stopped the Node.js service and hit my public IP. NGINX was still up but returned 502. That was the key lesson: 502 does not mean NGINX is down. It means NGINX cannot get a valid response from upstream.

How I Found the Real Cause

  1. Checked config syntax (this does NOT check if backend is running):
 bash sudo nginx -t 2. Checked real error: sudo tail -n 50 /var/log/nginx/error.log 28906#28906: *10 connect() failed (111: Connection refused) while connecting to upstream, upstream: "http://127.0.0.1:3000/" 3. Verified with curl: curl -i http://127.0.0.1:3000 curl -i http://127.0.0.1 I explained how I track Linux processes and debug ports with `ps aux | grep node`, `systemctl status` and `netstat -tulpn` in my earlier post about https://blog.sirvickcloud9.online/2025/09/understanding-linux-environment-real.html. How I Restored and Verified Instead of just restarting, I verified the actual HTTP response: curl http://127.0.0.1:3000 Hello! The Node.js backend is working correctly. curl -i http://127.0.0.1 HTTP/1.1 200 OK Always verify with real HTTP response, not just `systemctl status`. The Best Part: Testing systemd Auto-Restart On Ubuntu, systemd can restart your app automatically: in nginx-502-lab.service Restart=on-failure This is the same systemd approach I used when https://blog.sirvickcloud9.online/2025/10/my-github-actions-self-hosted-runner-kept.html — I fixed it by running it as a systemd service with `svc.sh`. Check logs: sudo journalctl -u nginx-502-lab -n 50 --no-pager My logs showed: Main process exited, code=killed, status=9/KILL Scheduled restart job, restart counter is at 1. Node.js application listening on 127.0.0.1:3000 After auto-restart, curl returned 200 OK again. Key Lessons - `sudo nginx -t` checks syntax only, not backend health - Always check `error.log` for `Connection refused` - Test both direct backend and through NGINX - `Restart=on-failure` helps, but you still need monitoring *I posted the full experiment with 4 screenshots, all commands, and production improvements on my blog:* *→ Read full lab: https://blog.sirvickcloud9.online/2026/10/how-i-fixed-nginx-502-bad-gateway-error.html* Thanks for reading SirVick DevOps Diary — I share practical labs from Port Harcourt as I learn AWS, Linux and DevOps. --- If this saved you time fixing 502, support my next lab: https://app.raenest.com/invoice/payment/RNMX5R3WP