A slow server is usually short of one of four things: CPU, memory, disk or network. These are the built-in commands that tell you which one, and which process is to blame — plus what the numbers actually mean, since a few of them are famously misread.
The 10-second health check
uptime free -h df -h
Three commands, three questions: is the CPU overloaded, is memory running out, is a disk filling up?
CPU: read the load average correctly
uptime # 14:02:11 up 12 days, 3 users, load average: 3.84, 2.10, 1.05 nproc # 4
The three load numbers are averages over the last 1, 5 and 15 minutes. Compare them with the number of CPU cores from nproc: a load of 3.84 on 4 cores means the CPU is nearly fully used; on 2 cores it means work is queuing up. Rising numbers from right to left (1.05 → 2.10 → 3.84) mean load is climbing.
To see which process is using it:
top
Inside top, press P to sort by CPU, M to sort by memory, 1 to see each core, and q to quit. htop (sudo apt install htop) shows the same with colours and mouse support. In the %Cpu line, a high wa value means the CPU is waiting for the disk — the disk is the real bottleneck, not the CPU.
Memory: look at "available", not "free"
free -h # total used free shared buff/cache available # Mem: 3.8Gi 1.9Gi 180Mi 12Mi 1.7Gi 1.6Gi # Swap: 2.0Gi 64Mi 1.9Gi
Linux uses spare memory as disk cache, so free is almost always small — that's good, not a problem. The number that matters is available: how much programs can still get. Worry when it drops below about 10% of total, or when swap use keeps growing.
The processes using the most memory:
ps aux --sort=-%mem | head
When memory ran out completely, the kernel killed something to recover. Find out what:
sudo dmesg -T | grep -i "out of memory"
Disk: space, inodes and speed
df -h # space used per filesystem df -i # inodes: can run out before space does
A full disk breaks databases, logins and logging in confusing ways, so act at around 85%. To find what is taking the space on the root filesystem:
sudo du -xh / --max-depth=1 2>/dev/null | sort -h | tail
Run it again on the biggest folder to drill down. Usual suspects: /var/log, old Docker images (docker system df), and the systemd journal (sudo journalctl --vacuum-size=200M trims it).
If the disk has space but is slow, check how busy it is (sudo apt install sysstat first):
iostat -x 2 3
A %util near 100 means the disk can't keep up.
Network: how much traffic
ip -s link # bytes and errors per interface since boot sar -n DEV 1 5 # traffic per second, live (from sysstat)
A sudden jump in incoming traffic with no change on your site often means a scan, a flood, or a brute-force attack.
When the cause is an attack
An SSH brute-force attack starts a new sshd process for every login attempt. On a small server, thousands of attempts can push the load up on their own. Count them:
pgrep -c sshd
Dozens of sshd processes while you're the only one logged in means you're under attack. See who is trying to log in, then stop the attack.
Watching more than one server
These commands answer "what is wrong right now" on one machine. To see trends — and every server at once — you need something that records the numbers over time. ThreatGuard's agent reports CPU, memory, disk and network every 10 seconds, so you get each server's health on the same dashboard as the attacks hitting it, with charts for the last hour or day.