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.”
- Introduction
- What Made This Worse (Real Production Confusion)
- What 502 Bad Gateway Actually Means (Simple Explanation)
- Step 1: First Thing I Checked (Service Status)
- Systemd Service (Real Production Configuration)
- Step 2: Port Verification (This Revealed the Real Issue)
- Step 3: NGINX Configuration Mistake
- Step 4: Fix That Solved Everything
- Step 5: Logs Confirmed the Fix
- What Actually Caused the 502 Error
- Common Mistakes Developers Make
- Best Production Practices
- Final Result
- Final Thoughts
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.