--- title: "Linux Network Troubleshooting with ping, traceroute and ss" description: "Diagnose Linux network problems step by step with ip, ping, dig, traceroute, mtr, ss, netstat and nc, and learn to read their output to find where it breaks." category: "Network Configuration" language: en source: https://cubepath.com/docs/network-configuration/network-troubleshooting-with-commands-ping-traceroute-netstat-ss updated: 2026-09-25 --- # Linux Network Troubleshooting with ping, traceroute and ss When a website does not load or a service cannot reach its database, guessing wastes time. A short, ordered set of checks tells you whether the problem is on the server itself, in DNS, somewhere on the path, or in the service and its firewall. In this tutorial you will work through that order on Ubuntu 24.04 with `ip`, `ping`, `dig`, `traceroute`, `mtr`, `ss`, `netstat` and `nc`, and learn how to read what each command prints. ## Prerequisites To follow this guide you need: - A server running Ubuntu 24.04 LTS, such as a CubePath VPS. The commands also work on Debian 12; package names for Rocky Linux 9 are noted where they differ. - A non-root user with `sudo` privileges. - Console access from your provider's panel in case the network problem also cuts your SSH session. The examples use `example.com` as a remote host, `203.0.113.10` as a remote IP address and `eth0` as the network interface. Replace them with your own values. ## The troubleshooting order Work from the inside out and stop at the first check that fails: | Check | Question it answers | Tool | |-------|---------------------|------| | 1. Local configuration | Does the server have an address, a route and DNS servers? | `ip`, `resolvectl` | | 2. Reachability | Do packets get to the destination and back? | `ping` | | 3. Name resolution | Does the name resolve to the right address? | `dig` | | 4. Path | Where along the way are packets lost or delayed? | `traceroute`, `mtr` | | 5. Sockets | Is the service listening, and what connections exist? | `ss`, `netstat` | | 6. Port | Can a TCP connection to the service port be opened? | `nc` | ## Step 1 - Installing the tools Ubuntu 24.04 ships `ping` and `ss`, but not all the others. Install them in one go: ```bash sudo apt update sudo apt install iputils-ping traceroute mtr-tiny bind9-dnsutils net-tools netcat-openbsd ``` `net-tools` provides the legacy `netstat`, `bind9-dnsutils` provides `dig` and `mtr-tiny` is `mtr` without the graphical interface. On Rocky Linux 9 the equivalent is `sudo dnf install iputils traceroute mtr bind-utils net-tools nmap-ncat`. ## Step 2 - Checking the local network configuration Most "the network is down" problems on a single server are a missing address, a wrong default route or broken DNS settings. Start with the interfaces: ```bash ip -br address ``` ```output lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 198.51.100.20/24 2001:db8:10::20/64 fe80::be24:11ff:fe4a:10c2/64 ``` The interface must be `UP` and have the address you expect. Next, the routing table: ```bash ip route ``` ```output default via 198.51.100.1 dev eth0 proto static 198.51.100.0/24 dev eth0 proto kernel scope link src 198.51.100.20 ``` Without a `default via` line the server can only reach its own subnet. To see which route and source address the kernel would use for a given destination, ask it directly: ```bash ip route get 203.0.113.10 ``` Finally, check which DNS servers systemd-resolved is using: ```bash resolvectl status ``` Look for a `DNS Servers:` line under the global section or the interface. If it is empty, name resolution fails even when the network is fine. ## Step 3 - Testing reachability with ping `ping` sends ICMP echo requests and measures how long replies take. Always limit the count with `-c` so the command ends on its own: ```bash ping -c 4 203.0.113.10 ``` ```output PING 203.0.113.10 (203.0.113.10) 56(84) bytes of data. 64 bytes from 203.0.113.10: icmp_seq=1 ttl=57 time=12.4 ms 64 bytes from 203.0.113.10: icmp_seq=2 ttl=57 time=12.1 ms 64 bytes from 203.0.113.10: icmp_seq=3 ttl=57 time=12.3 ms 64 bytes from 203.0.113.10: icmp_seq=4 ttl=57 time=12.2 ms --- 203.0.113.10 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 12.1/12.2/12.4/0.1 ms ``` The summary line matters most. Packet loss above 0% on a wired link, or a large `mdev` (jitter), points to congestion or a faulty link. Ping the default gateway first (the address from `ip route`), then an external IP, then a name: the first step that fails tells you how far the problem reaches. Useful variations: ```bash ping -c 4 -6 example.com ping -c 4 -M do -s 1472 203.0.113.10 ``` The first forces IPv6. The second sends 1,500-byte packets with the "don't fragment" bit set (1,472 bytes of data plus 28 bytes of headers). If it fails with `message too long` while smaller packets work, there is an MTU problem on the path, a common cause of connections that open but hang when transferring data. > Note: many hosts and firewalls drop ICMP on purpose. A failed ping to a third-party server does not prove it is down; continue with the port test in Step 7 before drawing conclusions. ## Step 4 - Checking name resolution with dig If pinging an IP address works but pinging a name fails, the problem is DNS. Query the name with `dig`: ```bash dig example.com A +short ``` ```output 93.184.215.14 ``` Compare the answer from your configured resolver with a public one to find out whether the local resolver is the problem: ```bash dig @1.1.1.1 example.com A +short ``` To see which nameservers are authoritative and follow the whole delegation from the root, use `+trace`: ```bash dig example.com +trace ``` In the full (non `+short`) output, check the `status:` field in the header: `NOERROR` means the name exists, `NXDOMAIN` means it does not, and `SERVFAIL` usually means a broken or unreachable authoritative server or a DNSSEC failure. ## Step 5 - Finding where packets are lost with traceroute and mtr `traceroute` lists every router (hop) between you and the destination by sending probes with increasing TTL values: ```bash traceroute -n example.com ``` ```output traceroute to example.com (93.184.215.14), 30 hops max, 60 byte packets 1 198.51.100.1 0.412 ms 0.388 ms 0.371 ms 2 192.0.2.33 1.102 ms 1.095 ms 1.201 ms 3 * * * 4 203.0.113.77 11.884 ms 11.902 ms 11.870 ms 5 93.184.215.14 12.231 ms 12.198 ms 12.240 ms ``` `-n` skips reverse DNS lookups, which makes the output faster and easier to read. A hop with `* * *` followed by hops that answer is normal: that router simply does not reply to probes. Only stars that continue until the end of the trace indicate a real block or loss. By default `traceroute` uses UDP probes, which firewalls often drop. When the trace stops early, probe the actual service port with TCP instead (this requires root): ```bash sudo traceroute -n -T -p 443 example.com ``` A single trace is a snapshot. `mtr` combines ping and traceroute and sends many probes to every hop, which is what you want to prove intermittent loss or to send evidence to a provider: ```bash mtr -rwn -c 100 example.com ``` ```output HOST: web01 Loss% Snt Last Avg Best Wrst StDev 1.|-- 198.51.100.1 0.0% 100 0.4 0.4 0.3 0.9 0.1 2.|-- 192.0.2.33 0.0% 100 1.1 1.2 1.0 3.4 0.3 3.|-- ??? 100.0 100 0.0 0.0 0.0 0.0 0.0 4.|-- 203.0.113.77 0.0% 100 11.9 12.0 11.8 14.1 0.3 5.|-- 93.184.215.14 0.0% 100 12.2 12.3 12.1 13.0 0.2 ``` `-r` prints a report, `-w` uses wide host names, `-n` disables DNS and `-c 100` sends 100 probes per hop. Read loss from the end: if the final hop shows 0% loss, loss on an intermediate hop is only that router rate-limiting its replies. Loss that starts at one hop and continues on every hop after it is real loss at that point of the path. ## Step 6 - Inspecting sockets with ss Once the path is fine, look at the service itself. `ss` is the modern replacement for `netstat` and reads socket information straight from the kernel, so it is fast even on busy servers. List every listening TCP and UDP socket with the owning process: ```bash sudo ss -tulnp ``` ```output Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=16)) tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=880,fd=3)) tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1204,fd=6)) tcp LISTEN 0 151 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=1033,fd=21)) ``` The options are `-t` TCP, `-u` UDP, `-l` listening only, `-n` numeric ports and `-p` process (needs `sudo` to see other users' processes). Pay attention to the local address: `127.0.0.1:3306` accepts connections only from the server itself, while `0.0.0.0` or `*` accepts them on every interface. A service bound to loopback is a very common reason for "connection refused" from outside. Filter by port to check one service: ```bash sudo ss -tlnp 'sport = :443' ``` List established connections, optionally filtered by remote address: ```bash ss -tn state established ss -tn dst 203.0.113.10 ``` Count TCP connections per state to spot anomalies: ```bash ss -tan | awk 'NR > 1 {print $1}' | sort | uniq -c | sort -rn ``` ```output 412 ESTAB 128 TIME-WAIT 12 LISTEN 3 SYN-RECV ``` Thousands of `TIME-WAIT` sockets are normal on a busy web server. A growing number of `SYN-RECV` sockets suggests a SYN flood or clients that cannot complete the handshake, and many `CLOSE-WAIT` sockets point to an application that does not close its connections. For a quick overall summary, use `ss -s`. ### netstat equivalents `netstat` still works after installing `net-tools`, and you will find it in older documentation. The common commands map directly: | Task | netstat | ss / ip | |------|---------|---------| | Listening ports with process | `sudo netstat -tulnp` | `sudo ss -tulnp` | | All TCP connections | `netstat -tan` | `ss -tan` | | Summary statistics | `netstat -s` | `ss -s` (and `nstat`) | | Routing table | `netstat -rn` | `ip route` | | Interface counters | `netstat -i` | `ip -s link` | Prefer `ss` and `ip` on new systems: `net-tools` is no longer developed and is not installed by default. ## Step 7 - Testing a TCP port with nc `ping` only proves ICMP works. To know whether a client can actually open a connection to a service, test the port with `nc` from the client side: ```bash nc -zv -w 3 203.0.113.10 443 ``` ```output Connection to 203.0.113.10 443 port [tcp/https] succeeded! ``` `-z` only checks the connection without sending data, `-v` prints the result and `-w 3` gives up after three seconds. The failure message tells you where to look: - **`Connection refused`**: the packet reached the host but nothing listens on that port, or the service is bound to another address. Check with `ss -tlnp` on the server. - **`timed out`**: packets are being dropped, usually by a firewall on the server (`sudo ufw status verbose`), a network firewall or a security group in front of it. For an HTTP service, `curl` goes one layer further and shows DNS, connection and TLS details: ```bash curl -sv -o /dev/null https://example.com ``` ## Troubleshooting - **`ping: socket: Operation not permitted`** in a container: the container lacks the `NET_RAW` capability. Run the check from the host or use `nc` instead. - **`traceroute` shows only stars from the first hop**: outbound UDP is filtered. Retry with `sudo traceroute -T -p 443` or use `mtr --tcp -P 443`. - **`ss -p` shows no process names**: you ran it without `sudo`, so only your own processes are visible. - **Name resolution works with `dig @1.1.1.1` but not without it**: the local stub resolver or upstream servers are wrong. Check `resolvectl status` and the netplan configuration in `/etc/netplan/`. ## Conclusion You now have a repeatable order for network problems: confirm the local configuration with `ip`, test reachability with `ping`, verify DNS with `dig`, locate loss with `traceroute` and `mtr`, and check the service with `ss` and `nc`. As next steps, learn to capture packets with `tcpdump` when these tools are not enough, review your firewall rules with UFW or nftables, and save an `mtr` report of your normal paths so you have a baseline to compare against during the next incident.