“The network is down” is not a diagnosis. A connection crosses name lookup, routing, a destination port, TCP, usually TLS, and finally an application protocol. Test them in that order and the vague outage becomes one failed step.
🎙️ Published & recorded: ·
Your application writes bytes to a socket. TCP splits the byte stream into segments, tracks order, and retransmits missing data. IP puts those segments into packets and moves each packet toward a destination address. Ethernet or Wi-Fi carries frames across the current link. Routers care about IP; they do not understand your JSON error.
HTTP request bytes
↓ application
TLS records # when HTTPS is used
↓
TCP segments # ordered, reliable byte stream
↓
IP packets # source and destination addresses
↓
Ethernet / Wi-Fi frames # one local hop at a time
DNS translates a hostname into one or more IP addresses. IPv4 looks like four decimal numbers; IPv6 is hexadecimal and much larger. After resolution, IP routing chooses a path toward the address. A hostname can return different addresses by region, network, or time, so record the address the failing client actually received.
# Resolve without making a TCP connection
nslookup api.example.com
# or
dig api.example.com A +short
dig api.example.com AAAA +short
# Inspect the route, not the application
tracert api.example.com # Windows
traceroute api.example.com # Linux/macOS
Do not type a production IP into an HTTPS URL and call that a clean DNS test. TLS certificate selection and HTTP virtual hosts need the hostname. Use curl --resolve to pin an address while preserving the real host name.
An IP address gets traffic to a machine or network interface. A port gets it to a service. A listening socket is bound to a local address and port. A connected TCP socket is identified by source address, source port, destination address, and destination port, so thousands of clients can talk to the same server port at once.
client 192.0.2.44:53182 → 203.0.113.10:443 server
temporary port HTTPS listener
# See listeners
ss -lntp # Linux
netstat -ano | findstr LISTEN # Windows
lsof -nP -iTCP -sTCP:LISTEN # macOS/Linux
Error: listen EADDRINUSE: address already in use 0.0.0.0:3000. One: inspect port three thousand with ss, lsof, or netstat -ano. Two: map the PID to a process. Three: stop the stale instance gracefully, or configure a different port. Four: restart and verify exactly one expected listener. Killing every process named Node hides supervision bugs and can stop unrelated apps.Before application bytes flow, the client sends SYN, the server replies SYN-ACK, and the client answers ACK. This negotiates initial sequence numbers and confirms a path in both directions. After that, TCP presents an ordered byte stream. It has no messages: two writes can arrive as one read, and one write can require several reads.
client server
| -------- SYN, seq=x --------------> |
| <----- SYN-ACK, seq=y, ack=x+1 ---- |
| -------- ACK, ack=y+1 ------------> |
| ===== application byte stream ===== |
| -------- FIN ---------------------> | # orderly close
TCP reliability is not infinite patience. Retransmissions happen below your app, but the application still needs connect, read, and overall deadlines. A successful handshake proves only that something accepted TCP on that address and port. It does not prove TLS, authentication, or the requested HTTP route works.
Refused is a fast answer: the destination host or an active reject rule said nothing is accepting that connection. Timeout is silence: packets were dropped, routed nowhere useful, or replies could not return. Treating both as “server down” wastes the information the network already gave you.
Error: connect ECONNREFUSED 127.0.0.1:5432
Error: connect ETIMEDOUT 203.0.113.10:443
# Test only TCP reachability to the destination port
Test-NetConnection api.example.com -Port 443 # PowerShell
nc -vz api.example.com 443 # Linux/macOS
curl -v --connect-timeout 5 https://api.example.com/
127.0.0.1. Two: on the server, confirm the service is running. Three: inspect the listener's bound address and port. Four: test locally on the server, then from the client. If local works and remote is refused, inspect bind address, container publishing, and active reject rules.127.0.0.1 and ::1 are loopback addresses. Traffic never leaves that network namespace. A server bound to loopback accepts only local clients. Binding to 0.0.0.0 means listen on all IPv4 interfaces; it is not a destination that clients should use. In a container, localhost means that container, not the host and not another container.
# Reachable only inside the same host or container
server.listen(3000, "127.0.0.1")
# Reachable on the container's interfaces; publish separately
server.listen(3000, "0.0.0.0")
docker run -p 8080:3000 my-app
# Verify the actual bind
ss -lntp | grep :3000
LISTEN 0 511 127.0.0.1:3000 ...
curl http://127.0.0.1:3000. Two: inspect ss -lnt; if it shows 127.0.0.1:3000, change the app bind to 0.0.0.0. Three: verify the container publishes the port, for example host eight thousand eighty to container three thousand. Four: test the host port. Five: only then inspect host or cloud firewalls. Exposing the port cannot repair an app bound to container loopback.Private IPv4 ranges are reusable inside networks and are not routed across the public internet. A NAT gateway rewrites private source addresses and ports to a public address for outbound connections, then maps replies back. Unsolicited inbound traffic has no mapping unless you add port forwarding or a load balancer.
10.0.0.24:53182 → NAT → 198.51.100.7:62014 → internet
private host public mapping
Private IPv4:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
# Public-looking address from outside
curl https://ifconfig.example # use a trusted endpoint you control
NAT is not a security policy. Stateful mappings happen to block most unsolicited inbound traffic, but authorization belongs in a firewall and the application. Also remember carrier-grade NAT: two routers may translate the connection, making home port forwarding impossible without provider support, IPv6, a tunnel, or a relay.
A firewall rule usually considers protocol, source, destination, port, direction, interface, and connection state. Cloud networks add security groups and network ACLs before the host firewall. Kubernetes adds Services and NetworkPolicies. One green rule in one dashboard proves very little if another layer drops the same packet.
# Minimum question, stated precisely
Allow TCP from 198.51.100.0/24
to 10.0.2.15 destination port 443
with return traffic for established connections
# Linux host checks vary by system
sudo nft list ruleset
sudo ufw status verbose
# Windows
Get-NetFirewallProfile
Get-NetFirewallRule -Enabled True
An HTTPS request is a stack of dependencies. DNS returns an IP. TCP connects to a port. TLS authenticates the hostname and creates encryption. HTTP sends a method, path, headers, and body. Test in that order. My strong opinion: ping is a weak availability test. Many healthy servers block ICMP, while a machine that answers ping may have no working application.
# 1. DNS
nslookup api.example.com
# 2. TCP port
Test-NetConnection api.example.com -Port 443
# 3 and 4. TLS plus HTTP, with verbose evidence
curl -v --connect-timeout 5 https://api.example.com/health
# Bypass DNS while preserving hostname for TLS and HTTP
curl -v --resolve api.example.com:443:203.0.113.10 \
https://api.example.com/health
# Listener ownership
ss -lntp | grep :443
netstat -ano | findstr :443
lsof -nP -iTCP:443 -sTCP:LISTEN
Could not resolve host is DNS. Failed to connect is TCP. certificate verify failed is TLS identity or trust. An HTTP 404 proves DNS, TCP, and usually TLS worked; now inspect the Host header and path. Never use -k as the production fix for a certificate failure.Run the test from the machine or container that actually fails. A successful request from your laptop proves your laptop's path, not the production worker's path.
1. Record exact HOST:PORT and failing client location
2. Resolve A and AAAA; note the returned addresses
3. Test TCP to that exact port with a short deadline
4. On server: verify process + bound address + listener
5. Check container/service port publication
6. Check route, NAT, cloud rules, and host firewall
7. Test TLS with the real hostname
8. Send the smallest HTTP request; read status and headers
ECONNREFUSED → host answered; no listener or active reject
ETIMEDOUT → dropped path, wrong route, or missing return path
EADDRINUSE → another socket already owns address and port
404 → network stack worked; inspect host/path/routing
TLS error → TCP worked; inspect name, chain, date, trust
localhost → this network namespace only
0.0.0.0 → listen on all IPv4 interfaces; not a client address
ping works → only ICMP replied
ping fails → server may still be healthy
Best evidence: timestamp, client, resolved IP, HOST:PORT,
listener output, curl -v trace, and firewall packet counters.
The rule worth keeping is simple: name the failed layer before changing anything. Resolve the name, reach the address, connect to the port, verify TLS, then speak HTTP. “Networking” becomes manageable when each test asks one question and the next action follows from the exact answer.