Home DevOps Linux Networking Commands Explained — Diagnose, Monitor and Debug Like a Pro

Linux Networking Commands Explained — Diagnose, Monitor and Debug Like a Pro

In Plain English 🔥
Imagine your computer is a post office. Networking commands are the tools the postmaster uses to check which delivery routes are open, which packages are stuck, and whether the roads between buildings are working. Just like a postmaster can trace a lost parcel or see which trucks are currently on the road, Linux networking commands let you trace packets, spot blocked ports, and see exactly which processes are talking to the outside world.
⚡ Quick Answer
Imagine your computer is a post office. Networking commands are the tools the postmaster uses to check which delivery routes are open, which packages are stuck, and whether the roads between buildings are working. Just like a postmaster can trace a lost parcel or see which trucks are currently on the road, Linux networking commands let you trace packets, spot blocked ports, and see exactly which processes are talking to the outside world.

Every production outage has a moment — usually at 2am — where someone types a networking command into a terminal and either finds the problem in 30 seconds or spends three hours guessing. Linux networking tools are what separates a DevOps engineer who can diagnose a flaky microservice from one who just restarts containers and hopes for the best. These commands are your stethoscope for the network layer.

ip vs ifconfig — Why the Old Tool Is Dead and What Replaced It

For years, ifconfig was the go-to command for inspecting network interfaces. It still works on many systems, but it's been deprecated and is no longer installed by default on modern Linux distributions like Ubuntu 20.04+ and RHEL 8+. The replacement is the ip command, which is part of the iproute2 package and talks directly to the kernel's netlink socket instead of parsing /proc files.

The key difference isn't just syntax — it's capability. ip can manage routing tables, network namespaces, tunnels, and ARP/NDP caches all through one unified tool. ifconfig could only touch interfaces and basic IP configuration.

When you're debugging a container networking issue in Kubernetes, you'll often drop into a pod's network namespace and run ip addr to see what the container thinks its IP is. That's impossible with ifconfig, which has no namespace awareness. Know ip deeply and you'll be comfortable anywhere from a bare-metal server to a Docker container.

network_interface_inspection.sh · BASH
123456789101112131415161718192021222324252627282930
#!/bin/bash
# Shows practical ip command usage for interface inspection
# Run these on any modern Linux host

# List all network interfaces with their IP addresses
# The 'addr' subcommand shows Layer 3 (IP) info bound to each interface
ip addr show

# Filter to just one interface — useful when you have many (eth0, lo, docker0, etc.)
ip addr show dev eth0

# Show the routing table — which gateway handles which destination networks
# This is the first thing to check when packets aren't leaving the host
ip route show

# Show the default gateway specifically — the 'exit door' for all unknown traffic
ip route show default

# Add a temporary static route for a specific subnet via a specific gateway
# This survives until reboot — use /etc/netplan or /etc/network/interfaces for persistence
ip route add 192.168.50.0/24 via 10.0.0.1 dev eth0

# Bring an interface DOWN and back UP without rebooting
# Useful after changing IP config or when an interface is in a bad state
ip link set eth0 down
ip link set eth0 up

# Check ARP cache — maps IP addresses to MAC addresses on your local network
# If a host's MAC shows as INCOMPLETE, ARP resolution is failing — suspect a firewall or VLAN issue
ip neigh show
▶ Output
# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
link/ether 52:54:00:ab:cd:ef brd ff:ff:ff:ff:ff:ff
inet 10.0.1.15/24 brd 10.0.1.255 scope global dynamic eth0

# ip route show default
default via 10.0.1.1 dev eth0 proto dhcp src 10.0.1.15 metric 100

# ip neigh show
10.0.1.1 dev eth0 lladdr 52:54:00:11:22:33 REACHABLE
10.0.1.20 dev eth0 lladdr 52:54:00:aa:bb:cc STALE
⚠️
Watch Out: ifconfig Changes Don't StickAny interface change made with ip (or ifconfig) is wiped on reboot. To persist changes, use your distro's config files — netplan YAML files on Ubuntu, nmcli/NetworkManager on RHEL, or /etc/network/interfaces on Debian. Making changes with ip and forgetting to persist them is a classic 'works until the server reboots' trap.

ss and netstat — Seeing Every Open Door on Your Server

Think of your server as a building with thousands of numbered doors (ports). ss and netstat let you see exactly which doors are open, who's standing at each one, and which processes are responsible. This is critical when deploying a new service — you need to know whether port 8080 is already taken before your app fails to bind to it.

netstat is the old tool, ss (Socket Statistics) is the modern replacement. ss talks directly to the kernel via netlink, which makes it dramatically faster on systems with thousands of connections. On a busy web server, netstat can take 10+ seconds while ss returns instantly.

The real power of ss is in its filtering. You can filter by state (ESTABLISHED, LISTEN, TIME_WAIT), by port, by process, or by remote address. In a microservices environment, you might want to see all connections from this service to the database on port 5432 — ss makes that a one-liner.

Understanding TCP connection states matters here. TIME_WAIT is normal and means your server is waiting for late packets before closing a connection. A flood of TIME_WAIT entries is usually fine. CLOSE_WAIT means the remote side closed but your application hasn't — that often points to a bug in connection handling code.

socket_inspection.sh · BASH
1234567891011121314151617181920212223242526272829
#!/bin/bash
# Practical ss usage patterns for diagnosing connection issues

# Show all LISTENING TCP ports with the process that owns them
# -t = TCP only, -l = listening sockets, -n = numeric (don't resolve hostnames, much faster),
# -p = show the process (requires root or sudo for processes owned by other users)
ss -tlnp

# Show all ESTABLISHED connections — who is currently connected to this server
ss -tn state established

# Find what's using a specific port (e.g., 8080)
# The 'sport' filter means 'source port' — the local port your service is bound to
ss -tlnp sport = :8080

# Count connections per remote IP — useful for spotting a single client hammering your API
# This pipes ss output through awk to extract remote IPs and count occurrences
ss -tn state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

# Show all UDP sockets (DNS, DHCP, NTP all use UDP — don't forget to check these)
ss -ulnp

# Show connection summary statistics by state
# Huge TIME_WAIT count is normal; huge CLOSE_WAIT count may indicate a connection leak
ss -s

# The netstat equivalent for those on older systems without ss
# -a = all sockets, -n = numeric, -t = TCP, -u = UDP, -p = process
netstat -antp
▶ Output
# ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1023,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=2150,fd=6))
LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=3201,fd=5))
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("node",pid=4422,fd=12))

# ss -s
Total: 234
TCP: 89 (estab 41, closed 12, orphaned 0, timewait 11)
UDP: 8
RAW: 0
FRAG: 0
⚠️
Pro Tip: 127.0.0.1 vs 0.0.0.0 in the Local Address ColumnWhen ss shows a service listening on 127.0.0.1:5432, it's only reachable from localhost — that's correct for a database. If it shows 0.0.0.0:5432, it's accepting connections from any interface — which may be a security misconfiguration. Always verify your database and internal services are NOT listening on 0.0.0.0 unless you have a firewall rule protecting them.

curl, wget and dig — Testing Connectivity Layer by Layer

When a service is unreachable, you need to narrow down the layer where things break. Is it DNS? TCP connectivity? HTTP routing? TLS? curl is exceptional here because it can test each layer independently and gives you precise timing data. dig is your dedicated DNS debugging tool, and together they let you methodically eliminate suspects.

curl's --verbose flag is one of the most useful things in networking debugging. It shows you the DNS resolution, the TCP handshake, the TLS negotiation, and the HTTP headers — all in sequence. When your HTTPS endpoint is slow, curl -w timing reveals whether the slowness is in DNS, in TCP, in TLS, or in the actual server response time.

dig is purpose-built for DNS and goes far beyond what you can learn from ping or curl. You can query specific record types, target specific nameservers, and trace the full delegation chain from root to authoritative server. This matters when you're investigating DNS propagation issues after a domain change, or debugging split-horizon DNS in a VPN setup.

wget is simpler and better for quick file downloads or when you need recursive mirroring. For API testing and network diagnosis, curl is almost always the right choice.

connectivity_layer_testing.sh · BASH
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
#!/bin/bash
# Test each networking layer independently to isolate where failures occur

# ─── DNS TESTING WITH dig ───────────────────────────────────────────────

# Basic A record lookup — what IP does this hostname resolve to?
dig api.example.com A

# Query a SPECIFIC nameserver (e.g., Google's 8.8.8.8) to bypass your local resolver
# Useful when debugging 'works on my machine' DNS issues caused by local caching
dig @8.8.8.8 api.example.com A

# Trace the full DNS delegation from root servers down to the authoritative nameserver
# This is the gold standard for debugging DNS propagation issues
dig +trace api.example.com

# Check MX records (mail routing) — +short gives just the values, no noise
dig api.example.com MX +short

# Reverse DNS lookup — find the hostname for an IP address
dig -x 93.184.216.34 +short

# ─── HTTP/HTTPS TESTING WITH curl ───────────────────────────────────────

# Follow redirects (-L), show verbose output (-v) — see every step of the connection
curl -Lv https://api.example.com/health

# Time each phase of the connection — invaluable for performance diagnosis
# This custom format prints timing for each phase on separate lines
curl -o /dev/null -s -w "
DNS lookup:        %{time_namelookup}s
TCP connect:       %{time_connect}s
TLS handshake:     %{time_appconnect}s
Time to first byte: %{time_starttransfer}s
Total time:        %{time_total}s
HTTP status code:  %{http_code}
" https://api.example.com/health

# Test an API endpoint with a JSON POST body — simulates what your app does
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token-here" \
  -d '{"username": "alice", "email": "alice@example.com"}' \
  --max-time 10  # fail after 10 seconds instead of hanging forever

# Test TLS certificate details — check expiry, issuer, and SANs
curl -vI https://api.example.com 2>&1 | grep -E '(subject|issuer|expire|SSL)'

# Skip TLS verification (ONLY for debugging self-signed certs — never in production)
curl -k https://internal-service.local/health
▶ Output
# dig api.example.com A +short
93.184.216.34

# curl timing output
DNS lookup: 0.012s
TCP connect: 0.034s
TLS handshake: 0.089s
Time to first byte: 0.201s
Total time: 0.203s
HTTP status code: 200

# If DNS takes 2+ seconds, your resolver is slow or the record isn't cached
# If TLS handshake takes 500ms+, suspect certificate chain or OCSP issues
# If 'time to first byte' is slow but TLS is fast, the app itself is the bottleneck
🔥
Interview Gold: The Layers of a Failed RequestInterviewers love asking 'how would you debug a service that users say is slow?' The layered answer — check DNS with dig, check TCP with ss/telnet, check HTTP timing with curl -w — demonstrates real operational thinking. Always start at the lowest layer (DNS) and work up. Jumping straight to application logs while skipping network diagnostics is the classic junior mistake.

ping, traceroute and tcpdump — Tracing the Path and Catching Packets

Once you've confirmed DNS resolves correctly and the service is listening, the next question is whether packets are actually reaching their destination. ping tells you if a host is reachable and measures round-trip time. traceroute shows you every hop between you and the destination. tcpdump lets you actually capture and inspect raw packets on the wire.

ping is often misused as a binary 'is it up?' test, but it's more nuanced than that. ICMP packets (what ping uses) can be blocked by firewalls while TCP traffic flows fine. A failed ping doesn't mean a service is down — it might just mean ICMP is blocked. Always follow up a failed ping with a TCP-level check.

traceroute reveals the routing path and where latency is introduced. Each hop shows you a router, and timing spikes between hops show you where delays occur. When a cloud VM can't reach an external API, traceroute often reveals the packet dying at a NAT gateway or security group that's silently dropping traffic.

tcpdump is the most powerful of the three but also the most complex. It captures actual packet data, which is essential for diagnosing issues that higher-level tools can't see — like retransmissions, RST floods, or malformed HTTP headers. Always combine it with Wireshark for complex analysis.

packet_path_tracing.sh · BASH
123456789101112131415161718192021222324252627282930313233343536373839404142434445
#!/bin/bash
# Trace packet paths and capture traffic for deep network diagnosis

# ─── PING ───────────────────────────────────────────────────────────────

# Basic connectivity check — send 5 packets, show statistics
ping -c 5 8.8.8.8

# Ping with a larger packet size to test MTU issues (1472 bytes + 28 byte IP/ICMP header = 1500 MTU)
# If this fails but small pings work, you likely have an MTU mismatch (common with VPNs)
ping -c 4 -s 1472 -M do 8.8.8.8  # -M do means 'don't fragment'

# ─── TRACEROUTE ─────────────────────────────────────────────────────────

# Standard traceroute using UDP probes
traceroute api.example.com

# Use TCP SYN probes on port 443 instead of UDP
# More likely to get through firewalls that block ICMP and UDP probes
traceroute -T -p 443 api.example.com

# mtr combines ping and traceroute — shows live packet loss per hop
# This is often the single best tool for diagnosing intermittent routing issues
mtr --report --report-cycles 20 api.example.com

# ─── TCPDUMP ────────────────────────────────────────────────────────────

# Capture all traffic on eth0 — CTRL+C to stop
# -n = don't resolve hostnames (faster), -i = interface
tcpdump -i eth0 -n

# Capture only HTTP traffic (port 80 or 443) to/from a specific host
# 'host' filters by IP in either direction
tcpdump -i eth0 -n host 10.0.1.20 and \( port 80 or port 443 \)

# Capture DNS queries — see what your server is resolving and to which nameserver
tcpdump -i eth0 -n port 53

# Save capture to a file for later analysis in Wireshark
# -w writes raw packets, -C 100 rotates files at 100MB to avoid filling the disk
tcpdump -i eth0 -n -w /tmp/capture.pcap -C 100 host 10.0.1.20

# Capture and print packet payloads in ASCII — see the actual HTTP request/response text
# -A = ASCII output, -s 0 = capture full packet (no truncation)
tcpdump -i eth0 -n -A -s 0 port 8080 | grep -E '(GET|POST|HTTP|Host:)'
▶ Output
# ping -c 5 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=4.21 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=4.18 ms
--- 8.8.8.8 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss
rtt min/avg/max/mdev = 4.18/4.22/4.31/0.04 ms

# traceroute -T -p 443 api.example.com
traceroute to api.example.com (93.184.216.34), 30 hops max
1 10.0.1.1 (10.0.1.1) 0.432 ms
2 203.0.113.1 (203.0.113.1) 3.211 ms
3 * * * <-- asterisks mean this hop is not responding (ICMP filtered)
4 93.184.216.34 12.44 ms

# mtr output (after 20 cycles)
Host Loss% Snt Last Avg Best Wrst
1. 10.0.1.1 0.0% 20 0.4 0.4 0.3 0.6
2. 203.0.113.1 0.0% 20 3.2 3.1 2.9 3.8
3. ??? -- hop doesn't respond to probes
4. 93.184.216.34 0.0% 20 12.4 12.3 12.0 13.1
⚠️
Pro Tip: Asterisks in traceroute Don't Mean Packet LossAsterisks (* * *) on a traceroute hop mean that router isn't responding to ICMP TTL-exceeded messages — not that your packets aren't passing through it. If the next hop appears and the final destination is reachable, that router is simply configured to drop probe packets silently. Only worry about asterisks if all subsequent hops also show asterisks.
CommandLayerBest Use CaseRequires Root?Modern Alternative
ifconfigLayer 3 (IP)Legacy interface config inspectionNoip addr
ipLayer 2-3Interfaces, routes, ARP, namespacesFor changes, yesStill current — no replacement
netstatLayer 4 (TCP/UDP)Port and socket inspectionFor -p flagss
ssLayer 4 (TCP/UDP)Fast socket stats, large systemsFor -p flagStill current — no replacement
pingLayer 3 (ICMP)Basic reachability and latency checkNoStill current
tracerouteLayer 3Routing path and hop latencyNomtr (combines with ping)
tcpdumpLayer 2-7Raw packet capture and inspectionYestshark (CLI Wireshark)
curlLayer 7 (HTTP/S)API testing, TLS and timing diagnosisNoStill current
digLayer 7 (DNS)DNS record queries and propagation debugNodrill (alternative on some distros)

🎯 Key Takeaways

  • ip and ss are the modern replacements for ifconfig and netstat — learn ip addr, ip route, and ss -tlnp as your default starting point on any system
  • Always debug network failures layer by layer: DNS first with dig, TCP connectivity second with ss/curl, then HTTP/TLS with curl -v, and packet-level last with tcpdump — jumping layers wastes time
  • tcpdump is your last resort, not your first — always filter by host and port, always write to a file with -w, and cap file size with -C to avoid filling disk on production servers
  • Asterisks in traceroute and a failed ping are not proof of failure — ICMP is routinely blocked by firewalls while TCP traffic flows freely, so always verify with a TCP-level tool before declaring a host unreachable

⚠ Common Mistakes to Avoid

  • Mistake 1: Using ping to confirm a service is down — Symptom: ping fails so you conclude the server is unreachable, but SSH and HTTP still work — Fix: ICMP is frequently blocked by cloud security groups and firewalls. Always follow a failed ping with a TCP check: 'curl -v telnet://hostname:22' or 'ss -tn' from the server itself to confirm the service is actually listening.
  • Mistake 2: Running tcpdump without a filter on a busy server — Symptom: terminal freezes or disk fills within seconds on a server handling thousands of connections per second — Fix: Always specify a host, port, or protocol filter: 'tcpdump -i eth0 host 10.0.1.20 and port 443'. Add '-w filename.pcap' to write to a file instead of flooding stdout, and use '-C 50' to cap file size at 50MB.
  • Mistake 3: Trusting a single DNS resolver when debugging resolution failures — Symptom: 'dig api.example.com' returns an IP but the service still can't connect from your app — Fix: Your app may be using a different resolver than your shell. Use 'dig @127.0.0.53 api.example.com' to query systemd-resolved specifically, 'cat /etc/resolv.conf' to see which resolver is configured, and compare results. Containers often have their own /etc/resolv.conf pointing to a different resolver entirely.

Interview Questions on This Topic

  • QA user reports that a web service is intermittently unreachable but your monitoring shows the server is up. Walk me through exactly how you would diagnose this — which commands would you run and in what order?
  • QWhat's the difference between a port that shows as LISTEN on 127.0.0.1 versus 0.0.0.0 in ss output, and why does it matter from a security perspective?
  • QYou run traceroute to an external API endpoint and see the third hop returns asterisks (* * *) but the final destination is reachable with normal latency. Is there a problem, and how do you explain this to a non-technical stakeholder?

Frequently Asked Questions

What is the difference between ss and netstat in Linux?

Both show socket and port information, but ss is the modern replacement for netstat. ss communicates directly with the Linux kernel via netlink sockets, which makes it far faster on systems with thousands of connections. netstat relies on parsing /proc filesystem files, which becomes slow under high load. On modern distributions (Ubuntu 20.04+, RHEL 8+), netstat may not even be installed by default — use ss -tlnp instead.

How do I find which process is using a specific port in Linux?

Run 'sudo ss -tlnp sport = :PORT_NUMBER' replacing PORT_NUMBER with the port you're investigating — for example 'sudo ss -tlnp sport = :8080'. The -p flag shows the process name and PID. You need sudo because processes owned by other users aren't visible without root privileges. Alternatively, 'sudo lsof -i :8080' also works and gives similar output.

Why does ping fail but the service is still accessible in a browser?

ping uses ICMP, which is a completely different protocol from TCP (which HTTP and HTTPS use). Cloud providers like AWS and GCP block ICMP by default in their security groups and firewall rules. So a host can be fully accessible via HTTP on port 80 while refusing to respond to ping entirely. This is intentional — exposing ICMP can enable network reconnaissance. Always use a TCP-based check like 'curl -v http://hostname' to confirm a service is truly unreachable, not just ping.

🔥
TheCodeForge Editorial Team Verified Author

Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.

← Previouscron Jobs in LinuxNext →SSH and SCP Explained
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged