Web Development Tutorials

Server Administration

Check Disk, Memory and CPU Usage From the Terminal

Check disk, memory and CPU usage from the terminal and a slow server stops being a guess. Four commands answer almost every question: df for free space, du for what consumed it, free for memory, and top for the processes. None of them change anything, so all are safe on a live box. First, this tutorial finds the full filesystem. Next, it tracks down the directory responsible. Finally, it reads memory, load average and the worst offending process.

Requirements to check disk, memory and CPU usage:

  • A Linux server you can reach over SSH (tested on Ubuntu 24.04.4 LTS, an AWS EC2 instance with 2 vCPUs and 1.8 GB of RAM).
  • sudo for the du examples, because parts of /var are not world-readable.
  • Nothing to install. Every command below ships with the base system, apart from htop.

How To Check Disk, Memory and CPU Usage.

The objective is a diagnosis in under a minute: which resource is short, and which file or process is to blame. Start with an SSH connection to the server, then work through the four commands in order.

Step 1.

First, ask how much disk is left. The -h flag prints human-readable sizes rather than blocks.

df -h
Filesystem       Size  Used Avail Use% Mounted on
/dev/root         29G  8.0G   21G  29% /
tmpfs            919M     0  919M   0% /dev/shm
tmpfs            368M  956K  367M   1% /run
/dev/nvme0n1p16  891M  149M  680M  18% /boot
/dev/nvme0n1p15   98M  6.4M   92M   7% /boot/efi
tmpfs            184M   12K  184M   1% /run/user/1000

Read the Use% column and ignore the tmpfs rows, which live in RAM. Here /dev/root is the real filesystem at 29% of 29 GB. Above 90% you are close to trouble, because a full disk stops MySQL writing and takes the site down.

Step 2.

Next, find what is using the space. df reports the total, whereas du walks a directory and adds up the files inside it.

# one line per directory, largest last
sudo du -h --max-depth=1 /var/log | sort -h
1.8M	/var/log/amazon
5.5M	/var/log/nginx
6.4M	/var/log/sysstat
326M	/var/log/journal
374M	/var/log

The systemd journal is 326 MB of the 374 MB total, so that is where the space went. Repeat the command one level deeper to narrow it further, or point it at the site itself.

sudo du -h --max-depth=1 /var/www/ndriel.com/httpsdocs | sort -h
11M	/var/www/ndriel.com/httpsdocs/wp-admin
68M	/var/www/ndriel.com/httpsdocs/wp-includes
124M	/var/www/ndriel.com/httpsdocs/wp-content
202M	/var/www/ndriel.com/httpsdocs

sort -h is what makes this readable, since it sorts 1.8M before 326M instead of alphabetically. Uploads and logs are the two directories that grow without anyone deciding they should.

Step 3.

Then, look at memory. The numbers confuse everyone the first time, because Linux deliberately spends free memory on cache.

free -h
               total        used        free      shared  buff/cache   available
Mem:           1.8Gi       777Mi       178Mi       132Mi       1.2Gi       1.0Gi
Swap:          2.0Gi        76Mi       1.9Gi

Read the available column, not free. Only 178 MB is genuinely unused, yet 1.0 GB is available, because the 1.2 GB of buff/cache is disk cache the kernel hands back on demand. A low free value is normal and healthy. Watch the swap row instead: 76 MB used here is fine, but a server actively swapping is a server about to crawl.

Step 4.

Now check the CPU. uptime is the fastest answer, and the three load averages cover the last 1, 5 and 15 minutes.

uptime
nproc
 01:20:39 up 24 days, 12:47,  1 user,  load average: 0.17, 0.06, 0.02
2

Load average counts processes waiting to run, so compare it against the core count from nproc. On these 2 cores, 2.0 means fully busy and 0.17 means idle. Therefore a load of 4 on a 4-core box is fine, while the same figure on a 1-core box is a queue.

Step 5.

Finally, name the process. top in batch mode prints one snapshot and exits, which makes it usable over SSH and in scripts.

top -bn1 | head -8
top - 01:20:39 up 24 days, 12:47,  1 user,  load average: 0.17, 0.06, 0.02
Tasks: 151 total,   1 running, 150 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1836.9 total,    178.9 free,    777.1 used,   1198.9 buff/cache
MiB Swap:   2048.0 total,   1971.7 free,     76.3 used.   1059.8 avail Mem

The id figure is idle CPU and wa is time spent waiting on disk. A high wa with low us means the bottleneck is storage, not processing. To rank processes instead, sort ps by memory or CPU.

ps aux --sort=-%mem | head -3
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
mysql     510480  0.0 11.4 1576460 216204 ?      Ssl  Aug01  11:22 /usr/sbin/mariadbd
nd-web   1032726  4.0  4.3 263896  82024 ?       S    01:20   0:00 php-fpm: pool ndriel

Swap -%mem for -%cpu to rank by processor time instead. For a live, colour-coded view there is htop (3.3.0 here), though it is interactive and needs a real terminal.

Result when you check disk, memory and CPU usage.

Four commands, four answers, and no changes to the server. This is the real output from the ndriel.com production box:

ubuntu@ip-172-31-20-62:~$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  8.0G   21G  29% /

ubuntu@ip-172-31-20-62:~$ sudo du -h --max-depth=1 /var/log | sort -h | tail -3
6.4M	/var/log/sysstat
326M	/var/log/journal
374M	/var/log

ubuntu@ip-172-31-20-62:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           1.8Gi       777Mi       178Mi       132Mi       1.2Gi       1.0Gi
Swap:          2.0Gi        76Mi       1.9Gi

ubuntu@ip-172-31-20-62:~$ uptime
 01:20:39 up 24 days, 12:47,  1 user,  load average: 0.17, 0.06, 0.02

Check disk, memory and CPU usage from the terminal: df shows 29% used, du finds the 326 MB journal, free reports 1.0 GB available and uptime shows a load average of 0.17

Notes on how to check disk, memory and CPU usage:

  • A disk can fill without filling. df -h may show space free while writes still fail, because the filesystem ran out of inodes instead. Check that with df -i, which usually points at a directory holding millions of tiny files.
  • Deleting a file a process still has open frees nothing. The space returns when that process closes the handle or restarts, and sudo lsof +L1 lists the culprits.
  • An oversized journal is capped, not deleted. sudo journalctl --vacuum-size=100M trims it immediately, and SystemMaxUse=100M in /etc/systemd/journald.conf keeps it there.
  • Application logs grow forever unless something rotates them, which is what a scheduled cron job is usually doing on a healthy server.
  • A one-off snapshot hides spikes. vmstat 5 or sar -u shows a trend, and the trend is what tells you whether the server needs more memory or just a restart.
  • Memory pressure often surfaces as a dead PHP worker rather than an error. If a systemd service keeps restarting, check available memory before assuming the service is at fault.

References:

//

Featured tutorial

Leave a comment

Your email address will not be published. Required fields are marked *