Trace services, logs, and network
Inspect listeners and connections
Identify the process, address family, local address, port, and connection state behind a network symptom.
10 minute lesson
“The port is open” is incomplete. A listener can bind only to loopback, one interface, IPv4, IPv6, or every address. Two services can even share a port number on different addresses. Until you know the exact binding, “it works here but not from the other machine” stays a mystery.
Inspect TCP port 3000
lsof -nP -iTCP:3000 -sTCP:LISTEN
-n and -P skip DNS and service-name lookups so you see raw addresses and ports. Typical output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 4821 flavio 23u IPv4 0x1a2b 0t0 TCP 127.0.0.1:3000 (LISTEN)
Read four things. COMMAND and PID identify the process — verify the PID with ps -p 4821 -o command to see the full path. USER tells you whose process it is. TYPE says IPv4 or IPv6, which matters because a server listening only on IPv6 is invisible to IPv4 clients. And NAME shows the bound address: 127.0.0.1:3000 accepts loopback connections only, while *:3000 accepts from any interface.
That last distinction solves the most common case: your dev server answers on localhost but not from your phone because it bound to 127.0.0.1, not 0.0.0.0.
See active connections too
Drop the state filter to include established connections:
lsof -nP -iTCP:3000
Now each line’s NAME shows local->remote pairs with a state like (ESTABLISHED) or (CLOSE_WAIT). A pile of CLOSE_WAIT entries points at an app not closing sockets it is done with.
The mistake to avoid
Match the PID to the expected executable and user before doing anything else. Do not kill an unknown listener just to free the port; identify who owns it and what depends on it. The “mystery” process on your port is often a legitimate system service or another project of yours, and killing it trades one symptom for two.
Lesson completed