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
sudoprivileges. - 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:
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:
ip -br address
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:
ip route
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:
ip route get 203.0.113.10
Finally, check which DNS servers systemd-resolved is using:
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:
ping -c 4 203.0.113.10
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:
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.
Notemany 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:
dig example.com A +short
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:
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:
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:
traceroute -n example.com
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):
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:
mtr -rwn -c 100 example.com
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:
sudo ss -tulnp
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:
sudo ss -tlnp 'sport = :443'
List established connections, optionally filtered by remote address:
ss -tn state established
ss -tn dst 203.0.113.10
Count TCP connections per state to spot anomalies:
ss -tan | awk 'NR > 1 {print $1}' | sort | uniq -c | sort -rn
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:
nc -zv -w 3 203.0.113.10 443
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 withss -tlnpon 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:
curl -sv -o /dev/null https://example.com
Troubleshooting
ping: socket: Operation not permittedin a container: the container lacks theNET_RAWcapability. Run the check from the host or usencinstead.tracerouteshows only stars from the first hop: outbound UDP is filtered. Retry withsudo traceroute -T -p 443or usemtr --tcp -P 443.ss -pshows no process names: you ran it withoutsudo, so only your own processes are visible.- Name resolution works with
dig @1.1.1.1but not without it: the local stub resolver or upstream servers are wrong. Checkresolvectl statusand 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.
