ERR_CONNECTION_REFUSED: what it means and how to fix it
Nothing is accepting connections on that port at all — a step below HTTP entirely, not a slow or broken response.
This is a TCP-level failure, not an HTTP one — your browser tried to open a connection to that host and port and got actively told no, rather than getting any kind of HTTP response back. Per RFC 9293 §3.5.2, when a connection attempt (a TCP SYN) arrives at a port with nothing listening, the underlying stack replies with a reset (RST) rather than accepting it — that reset is what shows up as "connection refused."
Overwhelmingly this is the target server's problem: either nothing is running there, a firewall is blocking the port, or the port number is simply wrong. A local firewall or VPN can occasionally cause the same symptom — worth ruling out by trying a different network before assuming it's the site.
A step below HTTP
Client
sends a TCP SYN to open a connection
Target host
nothing bound to that port — a reset is sent back
Notice there's no HTTP request in this picture at all — HTTP never gets a chance to start, because the underlying TCP connection it would run over was never established. This is a different failure class from a 502/503/504, which all require a connection to exist first.
Diagnosing ERR_CONNECTION_REFUSED
-
1
Check what's actually listening on the port. On the host itself,
ss -tlnp(ornetstat -tlnp) shows every bound port and which process owns it — if yours isn't in the list, that's the whole answer. -
2
Check which interface it's bound to. Bound to
127.0.0.1means only the same machine can reach it — everything external, including your own proxy, gets refused. It needs to bind0.0.0.0(or the specific external interface) to accept outside connections. -
3
Check firewall / security-group rules. A cloud provider's security group,
iptables, orufwrule blocking the port produces an identical symptom to nothing running at all. -
4
Confirm the process didn't crash without restarting. A process manager without a restart policy (no systemd
Restart=on-failure, no container orchestrator health check) leaves the port simply unbound after a crash, silently.
[Service]
ExecStart=/usr/bin/node /opt/app/index.js
Restart=on-failure
RestartSec=2
Without a restart policy, a crashed process just stays down until someone notices and restarts it by hand — the port stays refused the whole time.
Because no HTTP response ever arrives, the check records a connection failure directly rather than a status code — and if the endpoint has an HTTP status code assertion configured (the default for most checks), it fails with a message naming the underlying connection error, not a blank or misleading result. This is one of the more genuinely useful things external monitoring catches: a process manager running on the same host as your app can think everything's fine — the process is alive — while an interface-binding or firewall mistake makes it completely unreachable from outside. Only a check running from outside the host actually sees that.
Frequently asked questions
Is ERR_CONNECTION_REFUSED the same kind of error as a 502 or 504?
No — it's a layer below both. A 502 or 504 is an actual HTTP response that came back (just an unwelcome one). ERR_CONNECTION_REFUSED means no HTTP conversation ever started, because nothing was listening on that port to receive the connection in the first place. There's no status code involved because there was never a response to have one.
Could this be my own network's fault?
Occasionally — an overly aggressive local firewall or corporate proxy can produce the same symptom. But it's the exception, not the rule. If the same URL fails the same way from a different network (your phone on cellular data, for instance), it's almost certainly the server, not you.
Why would a running server still refuse the connection?
The most common real cause: it's bound to the wrong network interface. A process listening on 127.0.0.1 (localhost only) looks perfectly "running" to anything checking from the same machine, but refuses every connection from outside it — including a proxy or load balancer sitting in front of it, and definitely including an external monitoring check.
Does HeimPulse have a special check for this?
No dedicated check type — and it doesn't need one. Because no HTTP response ever comes back, HeimPulse's own HTTP request fails at the connection stage; the check records that failure directly, and an HTTP status code assertion (the most common assertion type configured on an endpoint) fails with a message naming the underlying connection error, not a fabricated status code.
Find out from outside, not from a customer's browser.
Free plan, no credit card, set up in a few minutes.