Skip to main content
Networking problems are responsible for a disproportionate share of outages and escalations. In over two decades of systems work I have found that most incidents boil down to one of three root causes: a routing or firewall rule that is wrong, a DNS entry that is stale or missing, or a service that is not actually listening on the expected address and port. The tools and workflows on this page address all three — methodically, without guessing.

Network Diagnostics

# Basic reachability
ping -c 4 8.8.8.8                   # 4 packets to Google DNS
ping -c 4 -I eth0 10.0.0.1          # bind to specific interface
ping6 -c 4 2001:4860:4860::8888     # IPv6

# Trace path to destination
traceroute 8.8.8.8                  # UDP probes by default
traceroute -T -p 443 google.com     # TCP to port 443 (bypasses ICMP blocks)
traceroute -I 8.8.8.8               # ICMP (like Windows tracert)

# mtr — combines ping + traceroute, live stats
mtr --report --report-cycles 20 8.8.8.8   # 20-cycle report mode
mtr -n --tcp --port 443 api.example.com   # TCP, no DNS resolution

# curl — test HTTP/S endpoints
curl -v https://api.example.com/health              # verbose output
curl -o /dev/null -s -w "%{http_code}\n" http://... # just the status code
curl -I https://example.com                         # HEAD request (headers only)
curl --max-time 5 -sf http://localhost:8080/health  # timeout + silent + fail on 4xx/5xx
curl -k https://self-signed.internal/api            # ignore cert errors
curl --resolve api.example.com:443:10.0.0.5 https://api.example.com/  # override DNS

# wget — alternative for downloading
wget -qO- http://checkip.amazonaws.com             # get external IP
wget --spider https://example.com                  # check URL without downloading

Interface Management with ip

The legacy ifconfig / route / netstat tools from net-tools are obsolete. Use ip and ss from the iproute2 suite on any modern Linux system.
ip addr show                         # all interfaces
ip addr show eth0                    # specific interface
ip addr show dev eth0                # same, explicit
ip -4 addr show                      # IPv4 only
ip -6 addr show                      # IPv6 only
ip -br addr show                     # brief one-line-per-interface format

# Add/remove address
sudo ip addr add 192.168.1.10/24 dev eth0
sudo ip addr del 192.168.1.10/24 dev eth0

Firewall Management

# Status
firewall-cmd --state
firewall-cmd --list-all               # active zone rules
firewall-cmd --list-all-zones         # all zones

# Allow a service (permanent = survives reboot)
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload                 # apply permanent changes

# Allow a specific port
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --remove-port=8080/tcp

# Allow a source IP
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" accept'

# Port forwarding
firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080

# Reload and verify
firewall-cmd --reload
firewall-cmd --list-all

SSH Power-User Tips

# Generate ED25519 key (preferred over RSA since ~2014)
ssh-keygen -t ed25519 -C "valeriy@hostname-$(date +%Y%m%d)" -f ~/.ssh/id_ed25519

# Copy public key to remote server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-host

# Manual alternative (when ssh-copy-id is unavailable)
cat ~/.ssh/id_ed25519.pub | ssh user@remote-host \
    "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

# Start ssh-agent and add key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l     # list loaded keys
Add ControlMaster auto, ControlPath ~/.ssh/cm-%r@%h:%p, and ControlPersist 10m to your ~/.ssh/config to multiplex SSH connections. After the first login, subsequent connections to the same host are near-instant with no re-authentication.

Common Port Reference

PortProtocolService
22TCPSSH
25TCPSMTP
53TCP/UDPDNS
80TCPHTTP
110TCPPOP3
143TCPIMAP
443TCPHTTPS
587TCPSMTP (submission)
3306TCPMySQL / MariaDB
5432TCPPostgreSQL
5672TCPRabbitMQ AMQP
6379TCPRedis
8080TCPHTTP alt / app servers
8443TCPHTTPS alt
9090TCPPrometheus
9200TCPElasticsearch HTTP
27017TCPMongoDB

DNS Troubleshooting Steps

1

Check the local resolver configuration

cat /etc/resolv.conf
# Look for: nameserver, search, domain directives

resolvectl status           # systemd-resolved details
resolvectl query google.com # query through systemd-resolved
2

Verify basic name resolution

# Does the host resolve at all?
dig +short google.com

# If that fails, try a public resolver directly
dig @8.8.8.8 +short google.com
dig @1.1.1.1 +short google.com

# If direct resolvers work but /etc/resolv.conf does not,
# the problem is local resolver configuration or caching
3

Check for DNS caching issues

# Flush systemd-resolved cache
resolvectl flush-caches
systemd-resolve --flush-caches

# Flush nscd cache (if running)
nscd -i hosts

# Verify TTL on the record (low TTL = propagating change)
dig +nocmd +noall +answer +ttl google.com
4

Trace the full delegation chain

# Follow the resolution from root servers down
dig +trace example.com

# Check all authoritative nameservers agree
for ns in $(dig +short NS example.com); do
    echo "=== ${ns} ==="
    dig @"${ns}" example.com A +short
done
5

Diagnose split-horizon / internal DNS

# Compare internal vs external resolution
dig @10.0.0.53 internal-app.company.com    # internal DNS
dig @8.8.8.8   internal-app.company.com    # external DNS

# Check search domain is set correctly
cat /etc/resolv.conf | grep search

# Test with FQDN (trailing dot forces full lookup)
dig internal-app.company.com.              # FQDN
6

Inspect /etc/hosts for overrides

grep -v '^#' /etc/hosts | grep -v '^$'
# Entries here override DNS — a common source of surprises
getent hosts hostname   # shows effective resolution order

Quick Network Diagnostics Checklist

# 1. Check interface is up and has an IP
ip -br addr show

# 2. Check default route exists
ip route show default

# 3. Ping the default gateway
GATEWAY=$(ip route show default | awk '/default/{print $3}')
ping -c 3 "${GATEWAY}"

# 4. Ping a public IP (bypasses DNS)
ping -c 3 8.8.8.8

# 5. Test DNS resolution
dig +short google.com

# 6. Test HTTP connectivity
curl -sv --max-time 5 https://google.com 2>&1 | head -30

# 7. Check local firewall
iptables -L OUTPUT -n -v
firewall-cmd --list-all   # if using firewalld
# 1. Is the service listening locally?
ss -tlnp | grep ':8080'

# 2. Is it bound to 0.0.0.0 or only 127.0.0.1?
ss -tlnp | grep ':8080'
# 127.0.0.1 means not reachable from outside

# 3. Test local loopback
curl -v http://127.0.0.1:8080/health

# 4. Test from the server's external IP
curl -v http://$(curl -s checkip.amazonaws.com):8080/health

# 5. Check firewall
iptables -L INPUT -n -v | grep 8080

# 6. Test from a remote host
nc -zv remote-host 8080
telnet remote-host 8080

Linux Essentials

Core commands including ss, ip, and file system tools.

Troubleshooting

Systematic workflows when networking is part of a larger incident.

Kubernetes

Kubernetes networking — Services, Ingress, and network policies.

AWS

VPC, security groups, and Route 53 in the cloud context.
Last modified on June 9, 2026