Fixing Nginx 'Connection Refused' Errors: A Practical Troubleshooting Guide
Encountering a 'Connection Refused' error when trying to access a service running behind Nginx is a common, yet frustrating, experience. Unlike a 'Timeout' error, which suggests network delay or packet loss, a 'Connection Refused' error is definitive: the operating system immediately rejected the connection attempt because no application was actively listening on the specified port and IP address.
This immediate rejection pinpoints the issue to a few critical areas: the service is down, the firewall is blocking the traffic locally, or the configuration directs traffic to a non-existent port. This guide provides a systematic, four-phase approach to diagnose and resolve 'Connection Refused' errors, ensuring you can quickly restore service connectivity.
Phase 1: Checking the Nginx Server Status (The Primary Listener)
The most basic cause of a connection refusal is that the Nginx service itself is not running or is configured improperly.
1. Verify Nginx Service Status
Use your system's service manager (usually systemd) to confirm that Nginx is active and running. A failure here is the direct cause of refusal on the primary listening port (usually 80 or 443).
sudo systemctl status nginx
Expected Output (Success): Look for Active: active (running).
Actionable Fix: If the status shows inactive or failed, attempt to start the service and check the logs for failure details.
sudo systemctl start nginx
sudo journalctl -xe | grep nginx
2. Confirm Active Listening Ports
Use the ss (socket statistics) or netstat tool to verify that Nginx is actually binding to the expected IP address and port (e.g., 0.0.0.0:80 or 127.0.0.1:8080).
# Using ss (preferred on modern Linux distributions)
sudo ss -tuln | grep 80
# Using netstat
sudo netstat -tuln | grep 80
If you do not see the expected port (e.g., :80 or :443) listed under a process (PID) associated with Nginx, it means Nginx failed to bind, likely due to a configuration error or another service already occupying that port.
Tip: If another service is occupying the port, you must either stop that service, or modify the Nginx configuration to listen on a different, available port.
Phase 2: Firewall and Network Configuration
If Nginx is running and listening locally, the connection refusal might be happening external to the service, typically due to firewall rules blocking inbound traffic.
1. Check Local Server Firewalls
Ensure that the ports Nginx is listening on (e.g., 80, 443) are explicitly allowed through the host's firewall (UFW, firewalld, or iptables).
UFW Example (Ubuntu/Debian)
sudo ufw status verbose
# If closed, allow the ports:
sudo ufw allow 'Nginx Full'
# Or specifically:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Firewalld Example (CentOS/RHEL)
sudo firewall-cmd --list-all
# If closed, add the services:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
2. Verify Cloud Provider Security Groups
If your server is hosted in a cloud environment (AWS EC2, Azure VM, GCP Compute Engine), the connection refusal might originate from the virtual network's security layer.
- AWS Security Groups (SG): Check the associated SG and ensure inbound rules permit traffic on ports 80 and 443 from the source IP addresses (usually
0.0.0.0/0for public access). - Azure Network Security Groups (NSG): Verify inbound port rules.
Phase 3: Nginx Configuration Validation
Incorrect configuration directives can lead Nginx to attempt listening on an unavailable port or IP, resulting in startup failure and subsequent connection refusal.
1. Review listen Directives
Inspect your primary configuration file (often /etc/nginx/nginx.conf) and any relevant server blocks (usually in /etc/nginx/conf.d/ or /etc/nginx/sites-enabled/). Ensure the listen directives are correct.
Example of a correctly configured listen block:
server {
listen 80;
listen [::]:80;
server_name example.com;
# ... other directives
}
If Nginx is configured to listen only on 127.0.0.1 (localhost) but you are attempting to access it using the public IP, the connection will be refused.
2. Run Configuration Syntax Check
Before restarting Nginx, always validate the configuration syntax. A parsing error will prevent the service from starting, causing the refusal.
sudo nginx -t
If the test fails, fix the identified error, re-run the test, and then reload or restart Nginx.
sudo systemctl reload nginx
Phase 4: Troubleshooting Reverse Proxy (Upstream) Issues
If Nginx is running successfully on ports 80/443, but accessing a specific path (/api/) results in 'Connection Refused,' the issue lies between Nginx and the backend service (the upstream).
In this scenario, Nginx accepted the initial connection, but when it tried to proxy the request, the connection to the backend was refused. The error logs will confirm this.
1. Check Nginx Error Logs
Examine the Nginx error logs (usually /var/log/nginx/error.log) immediately after attempting the failed connection. Look for messages related to the proxy_pass directive, specifically mentioning connection errors.
tail -f /var/log/nginx/error.log
You might see an entry like:
[error] connect() failed (111: Connection refused) while connecting to upstream
2. Verify Backend Service Status
This is the most common fix in proxy scenarios: the backend application (e.g., Node.js, Python Gunicorn, Apache) is down or not listening where Nginx expects it.
Actionable Steps:
a. Check Backend Service Status: Confirm the backend application is running.
b. Verify Backend Listening Port: Use ss -tuln on the server hosting the backend to confirm the application is listening on the IP/Port specified in Nginx's proxy_pass directive.
3. Test Backend Connectivity Directly
Test the connection from the Nginx server to the backend using curl or telnet to isolate the problem away from Nginx.
Suppose your proxy_pass is set to http://127.0.0.1:8080:
# Test connection from Nginx server to backend port
curl -v http://127.0.0.1:8080
# Or using telnet
telnet 127.0.0.1 8080
- If
curlortelnetfails: The backend service is definitely the issue (it's not listening or its internal firewall is blocking 127.0.0.1 access). - If
curlortelnetsucceeds: The issue might be a subtle error in yourproxy_passdirective (e.g., missing semicolon, incorrect hostname resolution, or a mismatch in protocol—HTTP vs. HTTPS).
Common proxy_pass Mistake
Ensure the IP address in your proxy_pass matches where the backend is actually bound. If the backend binds to a specific IP (e.g., 192.168.1.10:8080) but Nginx uses localhost:8080, the connection will fail if the binding is restrictive.
Summary of Key Troubleshooting Steps
- System Check: Is Nginx running (
systemctl status nginx)? - Port Check: Is Nginx listening on the correct IP/Port (
ss -tuln)? - Firewall Check: Is the incoming port open on the host firewall (UFW, iptables)?
- Config Check: Does
nginx -tpass, and arelistendirectives correct? - Proxy Check (If Applicable): Is the upstream service running and listening on the exact IP/Port defined in
proxy_pass? Test connectivity directly usingcurl.
By following this methodical process, you can quickly identify whether the 'Connection Refused' error is due to a dead service, a restrictive firewall, or a misconfigured proxy setup, minimizing downtime and restoring access efficiently.