This guide walks you through diagnosing and fixing a 502 Bad Gateway error when using Nginx as a reverse proxy in front of Gunicorn. The error means Nginx couldn’t get a valid response from Gunicorn, so you’ll check Gunicorn’s status, socket configuration, and Nginx’s proxy settings, then restart both services.
What You’ll Need
- SSH access to your server (or a terminal if running locally)
- sudo privileges
- Your project’s directory path (where your WSGI app lives)
- Basic familiarity with the command line
Step-by-Step
- Check if Gunicorn is running. Run
ps aux | grep gunicorn. If you see no gunicorn processes, it’s not running. If it’s running, note the PID and the bind address (e.g.,127.0.0.1:8000or a socket file). - If Gunicorn isn’t running, start it manually. Navigate to your project directory and run:
gunicorn --workers 3 --bind 127.0.0.1:8000 myapp:app(replacemyapp:appwith your WSGI entry point). If it starts without errors, the problem was simply that Gunicorn was down. If it fails, read the error output—it usually points to a missing module, a syntax error, or a permission issue. - If Gunicorn is running, test it directly. From your server, run
curl http://127.0.0.1:8000(or the address you configured). If you get HTML or a JSON response, Gunicorn is working. If you get a connection refused, it’s not listening on the expected address/port. - Check the Nginx error log. Run
sudo tail -f /var/log/nginx/error.logand then try to access your site. The log will show the exact upstream error, likeconnect() failed (111: Connection refused) while connecting to upstreamorupstream prematurely closed connection while reading response header from upstream. - Verify the Nginx configuration. Open your Nginx site config (usually in
/etc/nginx/sites-available/or/etc/nginx/conf.d/) and check theproxy_passdirective. It must match exactly where Gunicorn is listening. If Gunicorn is on127.0.0.1:8000, thenproxy_pass http://127.0.0.1:8000;is correct. If you’re using a Unix socket, it should beproxy_pass http://unix:/path/to/gunicorn.sock;. - Check file permissions for socket files. If you use a Unix socket, ensure the directory containing the socket is writable by the user that runs Gunicorn (often
www-dataorubuntu). Runsudo chown www-data:www-data /path/to/socketfile.sockif needed. - Restart both services. After any config change, run
sudo systemctl restart gunicornandsudo systemctl reload nginx. Then test your site again. - If using a systemd service for Gunicorn, check its status. Run
sudo systemctl status gunicorn. Look for lines likeActive: failedorActive: inactive (dead). If it failed,journalctl -u gunicornwill show the full error log.
Common Mistakes
- Mismatched bind addresses. Gunicorn listening on
127.0.0.1:8000but Nginx proxying tolocalhost:8000can cause issues if IPv6 is involved—use127.0.0.1explicitly. - Forgetting to restart Gunicorn after code changes. If your app crashes on startup, Gunicorn may stop. Always restart after deploying new code.
- Socket file paths with typos. A single character difference in the socket path will cause a 502. Copy-paste the path from one config to the other.
- Firewall blocking the port. If Gunicorn is on a non-standard port, ensure your firewall allows local connections (usually not an issue for localhost, but if Gunicorn is on a different interface, it matters).
Tips
- Use a systemd service for Gunicorn. It auto-starts on boot and restarts after crashes. Example unit file:
[Service] ExecStart=/usr/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 myapp:app. - Increase Gunicorn timeout for slow endpoints. If your app takes more than 30 seconds to respond, add
--timeout 60to the Gunicorn command. Nginx also has aproxy_read_timeout(default 60s) that you might need to increase. - Set the number of workers to
2 * CPU cores + 1. This is a common rule of thumb for CPU-bound apps. - Test Nginx config before reloading. Run
sudo nginx -tto catch syntax errors before applying.
Troubleshooting
If the 502 persists, work through these in order:
- Check if Gunicorn is actually running.
ps aux | grep gunicornagain. Sometimes it dies silently after starting. - Look at Gunicorn’s stdout/stderr. If you started it manually, the terminal shows the error. If it’s a service, use
journalctl -u gunicorn. - Try a simple test app. Create a file
test.pywithdef app(environ, start_response): ...and run Gunicorn on it. If that works, the issue is in your app’s code. - Check SELinux or AppArmor. On some systems, these can block Nginx from connecting to the socket. Temporarily set them to permissive mode to test (but re-enable after).
- Verify Nginx is running.
sudo systemctl status nginx. If it’s not running, start it. - Check for multiple Nginx configs. If you have both
sites-enabledandconf.dentries for the same domain, they can conflict. Disable one.
Frequently Asked Questions
Why does my 502 happen only on some requests?
That usually means Gunicorn is crashing or timing out on specific requests—often due to a memory leak or a very slow endpoint. Check Gunicorn’s logs for tracebacks, and consider increasing the timeout or the number of workers.
Should I use a TCP port or a Unix socket?
Unix sockets are slightly faster because they avoid TCP overhead, but they require proper file permissions. TCP ports are easier to debug and work across containers. If you’re just starting, use a TCP port like 127.0.0.1:8000.
What does ‘upstream prematurely closed connection’ mean?
This means Gunicorn accepted the connection but closed it before sending a full response. Common causes: the worker crashed (check Gunicorn logs), the request took too long and the worker was killed, or the app raised an unhandled exception that closed the socket.
Can a 502 be caused by Nginx itself?
Yes, but less often. A misconfigured proxy_pass (wrong URL, missing trailing slash) or a syntax error in the Nginx config can cause it. Always run sudo nginx -t after editing.
How do I fix a 502 after a server reboot?
If Gunicorn isn’t configured to start on boot, it won’t be running after a reboot. Create a systemd service and enable it with sudo systemctl enable gunicorn. Also ensure Nginx starts on boot with sudo systemctl enable nginx.
My Gunicorn log shows ‘Address already in use’. What now?
Another process (maybe a previous Gunicorn instance) is using the port. Find it with sudo lsof -i :8000 and kill it with sudo kill -9 PID, then start Gunicorn again.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Valheim Server Not Showing in Community List Fixes
- DisplayPort vs HDMI: Which Cable Should You Use?
- Soundbar vs 2.1 Speaker System: Which Is Better?
- Survive Lava for Brainrot Tier List170 points
- MySQL Dump Import: Fix Common Errors
- Mouse Moving on Its Own? Causes & Fixes