ERR_CONNECTION_REFUSED: what it means and the 4-step diagnosis
⏱️ 2 min read
What refused actually means
A refused connection is good news compared to a timeout: a machine answered and said nothing is listening on that port. Unlike a silent timeout (firewall dropping packets), refusal means the path works, the service does not.
The 4 checks, in order
- Is anything listening? On the target box:
ss -tlnp | grep :3000. Empty output = your app is not running or listening on a different port than you think. - Is it on the right interface?
127.0.0.1:3000is unreachable from outside, even with the firewall wide open. Inside containers, bind0.0.0.0if the port must be reachable past localhost. - Right host, right port?
curl -v telnet://host:portbeats guessing. Docker port maps-p 3000:3000can silently differ;docker port <container>tells the truth. - Firewall with REJECT rules. REJECT answers with refusal (iptables
--reject-with), which masquerades as no-listener.sudo iptables -L -n | grep -i rejector your cloud provider's security group: a blocked port on a cloud VM looks exactly like this. DigitalOcean and Vultr both apply their own firewall layer BEFORE the OS one, so check the provider console too.
The one-minute lab
nc -zv host 3000 # port open? ss -tlnp | grep 3000 # listening where? curl -v http://host:3000 # what exactly happens
If you need a scratch box to reproduce a refusal outside your laptop, an hourly VPS is the fastest tool: deploy one on Vultr and test from a second vantage point. (Partner link.)