DEV Community

Roger Oliveira
Roger Oliveira

Posted on Originally published at Medium

Connection refused" has three different root causes here's how to tell them apart with evidence

Connection refused" and a silent timeout look like the same failure to whoever's paging you at 2am. They're not. They come from different layers of the stack, and conflating them is why people restart services without ever fixing the actual cause.

The mental model:

Name (DNS) → Route to IP → Port open on target → Filter in the path → App responds

Reproduce it yourself (Docker required):

bash
docker network create rede-lab
docker run -d --name servidor --network rede-lab nginx:alpine
docker run -it --name cliente --network rede-lab busybox sh

Then break each layer independently:

DNS broken — overwrite /etc/resolv.conf inside the client container. Symptom: name doesn't resolve, but the same request by raw IP succeeds. That's your evidence it's DNS, not the network.
Port closed — stop nginx but keep the container alive. Symptom: immediate Connection refused. Evidence: ss -tlnp on the server shows nothing listening on port 80.
Firewall dropping — add an iptables -A INPUT -p tcp --dport 80 -j DROP rule. Symptom: silent timeout, no error. Evidence: tcpdump shows the SYN going out with no SYN-ACK coming back.

Reference table:

Symptom Likely cause Confirming evidence
Name doesn't resolve DNS Direct IP access works
Immediate refusal Port closed ss -tlnp shows nothing listening
Silent timeout Firewall DROP tcpdump shows unanswered SYN
Timeout with RST Firewall REJECT / closed port at OS level RST visible in tcpdump

The same three failure modes show up, renamed, in Kubernetes: DNS → misconfigured CoreDNS, closed port → empty Service Endpoints, firewall → a NetworkPolicy silently dropping traffic. Same method, different label.

Full write-up with the "why it matters for platform/SRE work" framing and the GitHub reference chapter (with an exercise checklist) are linked above.

Curious how people here debug this in practice: do you reach for tcpdump early, or only after ss/dig/nc rule out the obvious layers? And has anyone had a case where the symptom actively lied — e.g., a REJECT rule dressed up to look like a closed port? Drop it in the comments, I'm collecting real-world edge cases for the next chapter on containers.

Top comments (0)