🩺 Lesson 9: Disk, Memory and Network Checks

A five-minute health check you can run on any Linux machine: is there room, is there memory, and is the network alive?

Video: Disk, Memory and Network Checks (Linux 101 video)
Prefer to watch? This short video runs the lesson's main commands in a real Ubuntu 24.04 container, with on-screen captions and no voiceover. The disk and memory numbers shown come from the computer the container runs on. Click to play, or watch it on YouTube.

The five-minute health check

When a machine feels slow, or you have just been handed one you do not know, you do not guess. You ask a short list of questions and let the commands answer:

  1. How long has it been running, and how busy is it? uptime
  2. Is the disk full? df -h
  3. Is it out of memory? free -h
  4. Does it have a network address? ip -br address
  5. What is listening for connections? ss -tln

This lesson goes through each one, and then shows you how to work out whether a problem is "me" or "the network". Everything below, and the video, was run on a full Ubuntu 24.04 (a systemd container, the same kind of machine as in lesson 8). Two screens, the failed ping and the ssh login, are marked as coming from an earlier lab machine. (The tiny container from lesson 1 can run df, du and free, but it lacks the network tools.) The names and numbers on your machine will be different, and that is how it should be.

Disk space: df and du

ubuntu@practice:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay         915G  229G  640G  27% /
tmpfs            64M     0   64M   0% /dev
shm              64M     0   64M   0% /dev/shm
tmpfs            16G   52K   16G   1% /run
/dev/nvme0n1p2  915G  229G  640G  27% /etc/hosts
tmpfs            16G     0   16G   0% /run/lock
ubuntu@practice:~$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
overlay         915G  229G  641G  27% /
ubuntu@practice:~$ du -sh /usr/share
30M	/usr/share
ubuntu@practice:~$ du -h --max-depth=1 /usr
4.0K	/usr/lib64
4.0K	/usr/games
37M	/usr/bin
916K	/usr/libexec
52K	/usr/local
158M	/usr/lib
4.0K	/usr/src
30M	/usr/share
11M	/usr/sbin
24K	/usr/include
236M	/usr
ubuntu@practice:~$ du -sh /var/log
du: cannot read directory '/var/log/private': Permission denied
17M	/var/log
ubuntu@practice:~$ sudo du -sh /var/log
[sudo] password for ubuntu:
17M	/var/log
ubuntu@practice:~$ df -i /
Filesystem       Inodes   IUsed    IFree IUse% Mounted on
overlay        60981248 1901873 59079375    4% /

df means "disk free" and shows every filesystem that is mounted. The -h makes the sizes human readable (915G instead of a long number of kilobytes). The columns are Size, Used, Avail, Use% (how full it is) and Mounted on (where it appears in the folder tree).

Only a few rows matter. The first, mounted on /, is the main disk: 915 GB in total, 229 GB used, 27 percent full. (The numbers come from the computer the container runs on; a container shares its host's disk, which is why the filesystem is called overlay.) Rows like tmpfs and shm are memory pretending to be a disk, used for temporary files (/run, /dev/shm), and you can ignore them. df -h / asks about just one place. When the Use% of the main disk reaches 100, odd things break: programs cannot save, logs cannot be written, and you may not be able to log in.

So when it is getting full, which folder is to blame? That is the job of du, "disk usage":

A disk can also be "full" in another way: every file uses one inode (a small record), and a filesystem has a fixed number of them. df -i / shows that this disk has 60,981,248 inodes and uses 1,901,872, so 4 percent. Millions of tiny files can use up the inodes while there is still free space. The disk full runbook on this site covers that and more.

Memory: free, uptime and friends

ubuntu@practice:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:            31Gi       7.2Gi       971Mi       132Mi        22Gi        23Gi
Swap:          8.0Gi          0B       8.0Gi
ubuntu@practice:~$ nproc
8
ubuntu@practice:~$ uptime
 15:42:54 up 2 days, 22:57,  0 user,  load average: 1.67, 1.60, 1.42
ubuntu@practice:~$ head -3 /proc/meminfo
MemTotal:       32541184 kB
MemFree:          996408 kB
MemAvailable:   25024772 kB
ubuntu@practice:~$ hostnamectl
 Static hostname: practice
       Icon name: computer-container
         Chassis: container ☐
      Machine ID: 98ba59ae60964816acb85feb0c9fcff8
         Boot ID: 0a165fb5983f4b1caba9cb1c9081b6d4
  Virtualization: docker
Operating System: Ubuntu 24.04.5 LTS
          Kernel: Linux 7.0.0-38-generic
    Architecture: x86-64

Your network address: ip

ubuntu@practice:~$ ip -br address
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0@if210       UP             172.17.0.16/16
ubuntu@practice:~$ ip address show eth0
2: eth0@if210: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 6a:cf:2f:b0:da:00 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.16/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
ubuntu@practice:~$ ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.16
ubuntu@practice:~$ hostname -I
172.17.0.16

ping: is anybody there?

ubuntu@practice:~$ ping -c 3 localhost
PING localhost (::1) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.046 ms

--- localhost ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2078ms
rtt min/avg/max/mdev = 0.034/0.049/0.068/0.014 ms
ubuntu@practice:~$ ping -c 3 172.17.0.1
PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data.
64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from 172.17.0.1: icmp_seq=2 ttl=64 time=0.112 ms
64 bytes from 172.17.0.1: icmp_seq=3 ttl=64 time=0.081 ms

--- 172.17.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2072ms
rtt min/avg/max/mdev = 0.081/0.093/0.112/0.013 ms

For comparison, here is the same kind of ping on a different practice network (an earlier lab machine, not the one in the video), where it failed:

ubuntu@practice:~$ ping -c 3 archive.ubuntu.com
PING archive.ubuntu.com (185.125.190.82) 56(84) bytes of data.
From ubuntu-mirror-2.ps5.canonical.com (185.125.190.82) icmp_seq=1 Destination Port Unreachable
From ubuntu-mirror-2.ps5.canonical.com (185.125.190.82) icmp_seq=2 Destination Port Unreachable
From ubuntu-mirror-2.ps5.canonical.com (185.125.190.82) icmp_seq=3 Destination Port Unreachable

--- archive.ubuntu.com ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2002ms

ping sends a small test message and waits for the answer, over and over (we added -c 3: send exactly 3). Each reply line shows how long the round trip took, in milliseconds, and the summary at the end shows how many were lost.

Names: DNS and curl

ubuntu@practice:~$ getent hosts techcommune.org
47.204.6.48     techcommune.org
ubuntu@practice:~$ getent hosts nosuchname.invalid
ubuntu@practice:~$ curl -sI https://techcommune.org
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 22 Oct 2026 18:49:15 GMT
Content-Type: text/html
Content-Length: 8281
Last-Modified: Thu, 22 Oct 2026 12:18:07 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "6ad9feff-2059"
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'; object-src 'none'; frame-src https://www.youtube-nocookie.com
Cache-Control: no-cache
Accept-Ranges: bytes
ubuntu@practice:~$ curl -sI http://archive.ubuntu.com | head -n 3
HTTP/1.1 200 OK
Date: Thu, 22 Oct 2026 18:49:16 GMT
Server: Apache/2.4.58 (Ubuntu)

Computers use numbers, but people use names, so something has to translate. That is DNS, the phone book of the internet.

What is listening: ss

ubuntu@practice:~$ ss -tln
State        Recv-Q       Send-Q             Local Address:Port             Peer Address:Port      Process
LISTEN       0            4096                  127.0.0.54:53                    0.0.0.0:*
LISTEN       0            4096                     0.0.0.0:22                    0.0.0.0:*
LISTEN       0            511                      0.0.0.0:80                    0.0.0.0:*
LISTEN       0            4096               127.0.0.53%lo:53                    0.0.0.0:*
LISTEN       0            4096                        [::]:22                       [::]:*
LISTEN       0            511                         [::]:80                       [::]:*
ubuntu@practice:~$ sudo ss -tlnp
State         Recv-Q         Send-Q                 Local Address:Port                 Peer Address:Port        Process
LISTEN        0              4096                      127.0.0.54:53                        0.0.0.0:*            users:(("systemd-resolve",pid=71,fd=17))
LISTEN        0              4096                         0.0.0.0:22                        0.0.0.0:*            users:(("systemd",pid=1,fd=56))
LISTEN        0              511                          0.0.0.0:80                        0.0.0.0:*            users:(("nginx",pid=401,fd=5),("nginx",pid=400,fd=5),("nginx",pid=399,fd=5),("nginx",pid=398,fd=5),("nginx",pid=397,fd=5),("nginx",pid=396,fd=5),("nginx",pid=395,fd=5),("nginx",pid=394,fd=5),("nginx",pid=391,fd=5))
LISTEN        0              4096                   127.0.0.53%lo:53                        0.0.0.0:*            users:(("systemd-resolve",pid=71,fd=15))
LISTEN        0              4096                            [::]:22                           [::]:*            users:(("systemd",pid=1,fd=57))
LISTEN        0              511                             [::]:80                           [::]:*            users:(("nginx",pid=401,fd=6),("nginx",pid=400,fd=6),("nginx",pid=399,fd=6),("nginx",pid=398,fd=6),("nginx",pid=397,fd=6),("nginx",pid=396,fd=6),("nginx",pid=395,fd=6),("nginx",pid=394,fd=6),("nginx",pid=391,fd=6))

A service listens for connections on a numbered port, like a numbered door on the machine. ss shows the doors that are open. The options: -t is TCP connections, -l is listening ones, and -n shows plain port numbers. The Local Address:Port column tells you who may knock:

Adding -p shows which program owns each port, and it needs sudo to see other users' programs: users:(("nginx",pid=401,...)) names nginx and its process numbers (lesson 7). This is a powerful security check: if something is listening that you do not recognise, find out what it is. The site's [ss guide](site:docs/sysadmin/ss.html) goes much deeper.

ssh: logging in to another machine

Port 22 above is for SSH, the secure way to open a terminal on another computer, and the tool most administrators use every day. The form is ssh USER@MACHINE. To practise without a second machine, connect to yourself (this screen is from the earlier lab machine; the video did not run ssh):

ubuntu@practice:~$ ssh ubuntu@localhost
The authenticity of host 'localhost (::1)' can't be established.
ED25519 key fingerprint is SHA256:rCqweWI6ISgbEY69mRRgoBrf/K2RGsaHBQniSnoVxXY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
ubuntu@localhost's password:
Welcome to Ubuntu 24.04 LTS (GNU/Linux 7.0.2-6-pve x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

ubuntu@practice:~$ hostname
practice
ubuntu@practice:~$ exit
logout
Connection to localhost closed.

Passwords work, but real servers use key pairs instead, which are far safer. When you are ready, the site has guides on creating SSH keys and on hardening SSH.

Is it me, or is it the network?

When "the internet is not working", walk down this ladder from the bottom of the stack to the top. The first step that fails tells you where the problem is:

  1. **ip -br address**: do I have an address? If eth0 shows DOWN or has no address, the problem is the cable, the Wi-Fi or the network's address assignment, not the internet.
  2. **ip route**: is there a default via line? Without a gateway, nothing leaves your network.
  3. **ping -c 3 GATEWAY**: can I reach my router? If not, the problem is between you and the router.
  4. **getent hosts NAME: does a name turn into a number? If the numbers work but the names do not, the problem is **DNS. (This is why the old joke says it is always DNS.)
  5. **curl -sI https://NAME**: can I reach the real service? Trust this over ping.
  6. **sudo ss -tlnp** (on the server): is the service even listening? If you are the one running the service, this tells you whether it is up.
A SQL query walks into a bar, goes up to two tables and asks...<br>
"Can I join you?"

🧪 Try it yourself

On your full Ubuntu machine:

1. Find the Use% of your main disk with one df command. 2. Which folder directly under /usr is the biggest? (Use du -h --max-depth=1 /usr.) 3. How much memory is available, and is any swap used? 4. What are your machine's IP address and its default gateway? 5. Ping the gateway exactly twice. 6. Find the IP address of techcommune.org, then ask it for its headers with curl. 7. Which ports are open for the whole network (addresses starting with 0.0.0.0 or *)?

The cheat sheet

← Lesson 8 · ↑ All lessons · Lesson 10: Surviving a Text Editor →