Connection refused means the host was reachable but nothing accepted the connection on that port. This walk-through separates 'service down' from 'wrong port' from 'firewall reject'.
Check the listener: ss -tlnp | grep :PORT. A common trap: the app binds to 127.0.0.1 only, so remote connections are refused while localhost works.
Configs drift — the app may run on 8080 while you connect to 8081, or the container published a different host port than the container port.
REJECT returns a refusal (connection refused) rather than dropping (timeout). Check: sudo iptables -L -n | grep -i reject and ufw status verbose.
ss -tlnp | grep -E ':(80|443|8080|3000)\b' # look at the Local Address column
curl -v http://127.0.0.1:3000/ # works locally but not remotely = bind address problem
# typical app flags: --host 0.0.0.0 | app.listen(3000, '0.0.0.0') | docker run -p 3000:3000
sudo ufw status && sudo ufw allow 3000/tcp # or check cloud security-group rules
Refused vs. timeout is diagnostic gold: refused = reachable host, no listener; timeout = packets dropped or host/route down. In containers, -p host:container port mapping is a frequent source of 'works on my machine' refusals.
The service is probably listening only on 127.0.0.1. Run ss -tlnp — if the local address is 127.0.0.1:3000, remote clients will always be refused. Bind 0.0.0.0 (and firewall it properly).
No — if DNS failed you'd get name-resolution errors. Refused means TCP reached a live host and got an RST back. Use dig +short <host> to rule out resolving to the wrong IP.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.