How to Fix Nginx: Connection Refused While Connecting to Upstream
Quick Fix Summary
TL;DRCheck if your upstream application server (e.g., Node.js, Gunicorn) is running and listening on the correct port and interface.
Nginx cannot establish a TCP connection to the backend server defined in the `upstream` block or `proxy_pass` directive. This is a network-level failure, not an application error.
Diagnosis & Causes
Recovery Steps
Step 1: Verify Upstream Server Status
First, confirm the backend process is alive and bound to the expected port.
# Check if the service is running (e.g., for a systemd service)
sudo systemctl status your-app-service
# Or, check for listening ports on the upstream server
sudo ss -tlnp | grep :<your-port>
# Example: Check for a process on port 3000
sudo ss -tlnp | grep :3000 Step 2: Test Network Connectivity from Nginx Host
Rule out basic network issues by testing the connection from the Nginx server to the upstream.
# Use telnet or netcat to test the TCP connection
telnet <upstream-server-ip> <upstream-port>
# Or with netcat (nc)
nc -zv <upstream-server-ip> <upstream-port>
# Example: Test connection to 10.0.1.5 on port 8080
nc -zv 10.0.1.5 8080 Step 3: Inspect Firewall and Security Groups
Ensure no firewall (iptables, nftables, cloud security group) is blocking the traffic.
# Check iptables rules on the UPSTREAM server
sudo iptables -L -n -v | grep <nginx-server-ip>
# Check if the port is allowed in the INPUT chain
sudo iptables -L INPUT -n -v
# For AWS/Azure/GCP, verify the Security Group/NSG allows traffic from Nginx's IP on the upstream port. Step 4: Verify Upstream Binding Interface
A common mistake is the app binding only to localhost (127.0.0.1), making it unreachable from Nginx on another host.
# On the UPSTREAM server, check what IP your app is listening on.
# Look for 0.0.0.0 (all interfaces) or a specific IP. 127.0.0.1 is wrong for remote Nginx.
sudo netstat -tlnp || sudo ss -tlnp
# Example output showing problem:
# tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN 12345/node
# Fix: Configure your app (e.g., Node.js, Flask, Gunicorn) to listen on '0.0.0.0'. Step 5: Audit Nginx Upstream Configuration
Ensure the `upstream` block or `proxy_pass` directive points to the correct server and port.
# Check your Nginx config for the upstream definition
sudo nginx -T | grep -A 10 -B 2 "upstream"
sudo nginx -T | grep -B 5 -A 5 "proxy_pass"
# Example correct configuration:
upstream backend {
server 10.0.1.5:8080;
}
server {
location / {
proxy_pass http://backend;
}
} Step 6: Check Nginx Error Logs for Specifics
Nginx error logs provide the exact reason for the connection refusal. Tail them in real-time while reproducing the error.
# Tail the Nginx error log (common paths)
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/*.error.log
# Look for entries like:
# connect() failed (111: Connection refused) while connecting to upstream Architect's Pro Tip
"When using Docker, ensure your app container's port is published (`-p 8080:8080`) and the app inside listens on `0.0.0.0`, not `127.0.0.1`. Nginx outside Docker must use the host's IP, not `container_name`."
Frequently Asked Questions
My upstream server is on the same host as Nginx. Why do I get 'Connection Refused'?
This is almost always because your application server (e.g., Gunicorn, Node) is binding to `127.0.0.1` (localhost). Nginx connects via the loopback interface, but if the app only listens on a specific IP (like `127.0.0.1`), it works. However, if Nginx is configured to use the host's public IP or `localhost` resolves differently, it fails. The fix is to bind your app to `0.0.0.0` to listen on all network interfaces.
I fixed the issue, but Nginx still returns 502 Bad Gateway. What's wrong?
Nginx may be caching the failed upstream state. After confirming your upstream is healthy (using `nc -zv`), reload Nginx to clear its upstream connection cache: `sudo systemctl reload nginx`. Also, check the `proxy_next_upstream` and `proxy_connect_timeout` directives if the failure was intermittent.
What's the difference between 'Connection refused' and 'No route to host'?
'Connection refused' (ECONNREFUSED) means the TCP SYN packet reached the host, but nothing was listening on the target port. 'No route to host' (EHOSTUNREACH) is a lower-level network error where the host's IP address is not reachable at all, typically due to routing or firewall issues before the packet even arrives.