Network and time
Inspect listeners and firewalls
Connect a server process and bind address to host and cloud firewall policy for one exact flow.
8 minute lesson
A running service is reachable only if it listens on the intended address and every policy boundary allows the flow. “The service is up but I can’t connect” almost always breaks at one of three points: the bind address, the host firewall, or the provider firewall. Check them in that order.
What is actually listening
Use ss -lntup to identify the process, protocol, address, and port:
sudo ss -lntup
Netid State Local Address:Port Process
tcp LISTEN 127.0.0.1:3000 users:(("node",pid=2143,fd=18))
tcp LISTEN 0.0.0.0:22 users:(("sshd",pid=812,fd=3))
tcp LISTEN [::]:443 users:(("nginx",pid=1298,fd=6))
The Local Address column decides everything. 0.0.0.0 (or [::] for IPv6) means all interfaces — reachable from outside if firewalls allow it. 127.0.0.1 means loopback only. That node process on port 3000 will never answer a remote client, no matter what you do to the firewall. Loopback listeners are intentionally unavailable from remote clients; that’s often correct (an app behind nginx should bind to loopback), but it’s the first thing to rule out.
If the port doesn’t appear at all, the service isn’t the network’s problem — it failed to bind, and the reason is in its journal.
Walk the policy boundaries
Check host firewall and provider firewall rules separately, because either can silently drop the flow:
sudo nft list ruleset | grep -A2 'dport 443' # or: sudo ufw status
Then the cloud layer — security group, VPC firewall, or provider “networking” tab. Nothing on the host will show you a packet the provider dropped before it arrived. A capture proves it: run sudo tcpdump -ni any port 443 while a remote client connects. No SYN arriving means the block is upstream of the machine.
Prove it from a real client
Finish with a test from where users actually connect:
nc -vz -w 3 203.0.113.40 443
# Connection to 203.0.113.40 443 port [tcp/https] succeeded!
A timeout points at a filter along the path. An immediate refused means the packet arrived and nothing was listening on that address.
The trap: testing from the server itself. curl localhost:3000 succeeds over loopback and proves nothing about remote reachability — this is exactly how a loopback-only bind hides for hours. Choose one server port and record its listener, bind address, host rule, cloud rule, and a remote connection test.
Lesson completed