How I Fixed 502 Bad Gateway in NGINX for .NET App (Linux Production Deployment Issue Explained)

Introduction

There’s always that one moment in backend development that humbles you.

For me, it was a normal .NET deployment on a Linux server behind NGINX. Nothing fancy. Just a small API update.

I deployed it, refreshed the browser… and suddenly everything broke.

502 Bad Gateway.

No clear error. No crash. No logs pointing directly to the issue.

Just NGINX silently saying: “I can’t talk to your backend.”


What made this worse (real production confusion)

The worst part? Everything looked fine.

  • .NET service was running
  • Server was healthy
  • No restart issues

But the browser? Still showing 502 error.

That’s when I realized — this is not a code issue. This is a deployment communication issue.


What 502 Bad Gateway actually means (simple explanation)

In real-world production terms:

NGINX tried to send request to .NET backend but didn’t get a valid response.

That’s it. Simple but dangerous.

Most common causes in real production systems:

  • Wrong backend port
  • Kestrel not listening correctly
  • NGINX pointing to wrong service
  • Firewall blocking internal traffic

Step 1: First thing I checked (service status)

systemctl status my-dotnet-api.service

Service was active. Running fine.

journalctl -u my-dotnet-api.service -f

No crashes. No errors. That made debugging even more confusing.


Systemd Service (Real Production Configuration)


[Unit]
Description=ASP.NET Core App on Linux with NGINX

[Service]
WorkingDirectory=/home/azureadmin/webapps/kohamsa.com
ExecStart=/usr/bin/dotnet /home/azureadmin/webapps/kohamsa.com/KoHamsa.API.dll
Restart=always
RestartSec=10
User=azureadmin

Environment=ASPNETCORE_ENVIRONMENT=Development
Environment=ASPNETCORE_URLS=http://127.0.0.1:5004

[Install]
WantedBy=multi-user.target

Key point: The app was running on port 5004, not 5000.


Step 2: Port verification (this revealed the real issue)

ss -tulnp | grep dotnet
curl http://localhost:5000

No response.

curl http://localhost:5004

Instant response.

That was the root cause — port mismatch.


Step 3: NGINX configuration mistake


location / {
    proxy_pass http://localhost:5000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
}

NGINX was pointing to port 5000.

But .NET was running on 5004.


Step 4: Fix that solved everything

proxy_pass http://localhost:5004;
nginx -t
systemctl reload nginx

After reload… I tested again.

This time, response came instantly.


Step 5: Logs confirmed the fix

tail -f /var/log/nginx/error.log

Before fix:

connect() failed (111: Connection refused)

After fix:

No errors at all.


What actually caused the 502 error

Not code. Not server failure.

Just a simple mismatch:

  • NGINX → wrong port
  • .NET → correct port

That’s it.


Common mistakes developers make

  • Forgetting to update proxy_pass after deployment
  • Changing ASPNETCORE_URLS but not restarting service
  • Assuming service running = app working

Best production practices

  • Always verify port after deployment
  • Create /health endpoint
  • Check logs before restarting anything

Final result

After fixing the port mismatch, the application started working instantly.

System was not broken. Only misconfigured.

And that’s usually how real production issues are.


Final thoughts

502 Bad Gateway looks scary, but in real Linux + .NET deployments, it’s almost always a simple configuration mismatch.

Once you understand how NGINX talks to Kestrel, debugging becomes much faster.

Hope this saves you from hours of production headache.

f X W