Analyzing Nginx Error Logs for Connection Refused Troubleshooting

Learn how to trace Nginx connection refused errors from logs to the exact upstream service, port, socket, or network issue.

Analyzing Nginx Error Logs for Connection Refused Troubleshooting

Analyzing Nginx error logs for connection refused troubleshooting helps you move from a generic 502 page to a specific backend failure. The phrase "connection refused" usually means Nginx tried to connect to an upstream address, but no process accepted the connection.

That is different from a timeout, DNS failure, or bad response. Once you recognize the log pattern, you can narrow the fix quickly.

What "Connection Refused" Means

In Nginx logs, a common message looks like this:

connect() failed (111: Connection refused) while connecting to upstream

This means the operating system rejected the connection attempt. Nginx reached the target host, but nothing was listening on the target port, or the connection was actively refused.

You might see it when Nginx proxies to:

proxy_pass http://127.0.0.1:3000;

but the application is stopped or listening on a different port.

This error is common after deployments. A process manager may fail to restart the app, a container may crash, or a new config may change the app port without updating Nginx.

Do not treat every 502 as connection refused. A timeout message points in a different direction. A permission denied message often points to sockets or security policy. The exact log text matters.

Finding the Right Nginx Error Log

The default error log path is often:

/var/log/nginx/error.log

But server blocks can define custom logs:

error_log /var/log/nginx/app-error.log warn;

Check the relevant Nginx config if the default log does not show recent entries. On some systems, service-level messages also appear in the system journal.

Useful commands include:

tail -n 100 /var/log/nginx/error.log

and:

journalctl -u nginx -n 100

When testing, trigger one request in the browser or with curl, then immediately check the newest log lines. That makes it much easier to connect the user-facing error with the backend failure.

A good log review captures four pieces of information:

  • The timestamp of the failed request.
  • The upstream address and port.
  • The request path.
  • The exact system error, such as 111: Connection refused.

For broader Nginx troubleshooting, see fixing Nginx 502 Bad Gateway errors.

Mapping the Log Entry to the Upstream

A typical log line may include an upstream value like:

upstream: "http://127.0.0.1:3000/api/status"

That tells you exactly where Nginx tried to send the request. Now verify whether anything is listening there:

ss -ltnp

Look for 127.0.0.1:3000, 0.0.0.0:3000, or the expected address. If the port is missing, the app is not listening where Nginx expects it.

Test the upstream directly:

curl -i http://127.0.0.1:3000/api/status

If this fails with connection refused, you have confirmed the issue without Nginx in the middle.

If the app is running in Docker, be careful with 127.0.0.1. From the host, it means the host. From inside an Nginx container, it means the Nginx container itself. In a Compose setup, Nginx usually needs to proxy to a service name such as:

proxy_pass http://app:3000;

provided both containers share the same Docker network.

For Unix sockets, the log may point to a path instead of a port:

upstream: "http://unix:/run/app/app.sock:/"

In that case, check whether the socket exists and whether the Nginx worker user can access it.

Common Causes and Fixes

The most common cause is a stopped backend service. Check it with:

systemctl status your-app

If it failed, read the app logs before restarting. A restart may bring the site back, but the logs explain why it failed.

Another common cause is a port mismatch. For example, the app changed from port 3000 to 8080, but Nginx still proxies to 3000. Fix the Nginx upstream target or restore the app's expected port.

A third cause is binding to the wrong interface. An app listening only on 127.0.0.1 is reachable from local Nginx on the same host. But if Nginx runs in another container or another server, it will not be reachable through that loopback address. In those setups, the app may need to bind to 0.0.0.0 inside the private network.

Firewall rules can also refuse or reject connections, especially across servers. If Nginx proxies to another host, confirm that the upstream port is open from the Nginx machine, not only from your laptop.

Finally, deployment timing can cause brief connection refused errors. If Nginx sends traffic before the new app process is ready, users may see intermittent 502s. A health check, readiness probe, or graceful restart strategy can prevent that.

A Practical Troubleshooting Flow

Use this order when the log says connection refused:

  1. Copy the upstream host and port from the Nginx error log.
  2. Run curl to that exact upstream from the Nginx server.
  3. Run ss -ltnp to confirm a process is listening.
  4. Check the backend service status and application logs.
  5. Compare the Nginx proxy_pass value with the app's actual bind address.
  6. Reload Nginx only after the config is correct and nginx -t passes.

This flow prevents a common mistake: editing Nginx when the app is simply down. It also prevents the opposite mistake: restarting the app repeatedly when Nginx is pointing to the wrong place.

For command basics, see Nginx log monitoring commands.

When to Call a Professional

Get help when connection refused errors happen only under load, across multiple upstreams, or during rolling deploys. Those cases may involve process supervision, container networking, load balancer health checks, or capacity limits.

You should also escalate if the upstream is a production payment, authentication, or customer-facing API service. Fast recovery matters, but preserving logs and understanding the failure matters too.

Connection refused is one of the clearer Nginx errors once you read it carefully. Find the upstream in the log, test that target directly, and fix the service, port, interface, or network path that prevents Nginx from connecting. The log already gives you the starting point.