How to monitor RAM, CPU and disk on a Linux VPS in real time
Learn how to monitor RAM, CPU and disk on a Linux VPS in real time from the terminal using top, htop, vmstat, iostat and supporting tools.
When a VPS starts to feel slow, the first question is always the same: what is consuming resources. Without a graphical dashboard, the terminal is still the fastest and most accurate place to answer that. The right tools show in seconds whether the bottleneck is CPU, memory, disk or network — and what is causing it.
This tutorial is for sysadmins and developers who manage Linux VPS instances over SSH and want to master the native real-time monitoring tools. We cover top, htop, free, vmstat, iostat, df and du, with a focus on reading the numbers correctly — because most diagnostic mistakes come from misreading the output, not from a missing tool.
Estimated execution time: 20 to 30 minutes to run all the commands and understand the output of each one.
Prerequisites
You need a Linux VPS (Ubuntu 22.04 LTS, Debian 12 or Rocky 9 all work), SSH access with a sudo user and around 30 MB free to install the helper packages. Most tools ship with the base system; only htop, iotop and sysstat need to be installed.
Ubuntu 22.04+ / Debian 12 / Rocky 9 SSH + sudo htop, iotop, sysstat Installing the helper tools
Before you start, install the packages that do not ship by default. htop is the colorful interactive version of top, iotop shows I/O per process and sysstat brings iostat, pidstat and sar.
Update the package index:
sudo apt updateOn Rocky/AlmaLinux replace it with sudo dnf check-update. The index needs to be fresh in order to install recent versions.
Install htop, iotop and sysstat:
sudo apt install -y htop iotop sysstatOn Rocky/AlmaLinux: sudo dnf install -y htop iotop sysstat. The sysstat package needs to be enabled to collect historical data: sudo systemctl enable --now sysstat.
Monitoring CPU in real time
CPU is the most obvious resource to read, but many people forget to separate process usage, system (kernel) usage and I/O wait. Saturation caused by I/O wait shows up as slowness with no process apparently using CPU.
Run top to see the general summary:
topThe first line shows the 1, 5 and 15 minute load averages. The third line (%Cpu(s)) breaks down: us (userspace), sy (kernel), id (idle), wa (I/O wait), st (steal time — time taken by the hypervisor). Press 1 to see each vCPU separately, P to sort by CPU, M by memory, q to quit.
For a cleaner and more interactive view, use htop:
htophtop shows colored bars per vCPU, lists all processes with a parent/child tree (F5) and lets you kill processes with F9. Practical difference: colors indicate the type of usage — green is userspace, red is kernel, blue is low-priority. A dominant red almost always points to a problem (driver, excessive syscalls, contention).
In virtualized environments, the st column (steal time) shows CPU the hypervisor took from your machine to serve other tenants. Steal time consistently above 5% indicates an oversubscribed node — time to request a migration or switch providers.
Monitoring RAM
RAM on Linux is the most misread resource. The kernel uses all free memory as cache to speed up I/O, so a low free value is the normal state. The number that matters is available, not free.
Check current memory usage:
free -hTypical output on a 4 GB VPS:
total used free shared buff/cache available
Mem: 3.8Gi 1.2Gi 180Mi 50Mi 2.5Gi 2.4Gi
Swap: 2.0Gi 0B 2.0Giused 1.2 GB and available 2.4 GB means processes are consuming 1.2 GB and the kernel can release another 2.4 GB of cache on demand. Excellent health. Start worrying when available falls below 10% of total or swap starts growing.
To watch changes live:
watch -n 2 free -hwatch -n 2 re-runs the command every 2 seconds. Useful for observing behavior during a deploy, build or synthetic workload.
For time-granular data, use vmstat:
vmstat 1The first line is the average since boot — ignore it. The following ones print every 1 second. Watch si (swap in) and so (swap out): any value consistently above zero indicates real memory pressure. The r column (runnable processes) larger than the vCPU count for more than a few seconds points to CPU saturation.
Occasional swap during peaks is tolerable. Growing and sustained swap (so > 0 over time) degrades performance dramatically because disk is orders of magnitude slower than RAM. Consider upgrading the plan or finding the process that is leaking memory.
Monitoring disk usage
Disk has two dimensions: occupied space (capacity) and I/O speed (throughput). Each one has a dedicated tool.
Check space used per filesystem:
df -hShows each mount point with total, used, available and percentage. Watch / (root) and /var (logs, databases). A filesystem above 85% asks for cleanup; above 95% is an emergency — many services stop writing to avoid corruption.
To find who is taking up space, use du:
sudo du -h --max-depth=1 /var | sort -hLists each subdirectory under /var with its total size, sorted from smallest to largest. Repeat the command, descending into the largest entries. Replace /var with the directory you care about. The --max-depth=1 flag avoids a full recursive scan.
For live I/O, use iostat from sysstat:
iostat -xz 1-x shows extended statistics, -z omits devices with zero activity. Key metrics:
%util— percentage of time the disk is busy. Above 80% sustained indicates saturation.await— average latency in ms. A healthy SSD stays below 10 ms; HDD below 20 ms.r/sandw/s— read and write operations per second.
To see which process is doing I/O:
sudo iotop -oP-o shows only processes with active I/O, -P groups by process (rather than thread). Useful for identifying the culprit when iostat shows the disk saturated but you do not know who is hammering it.
Verification
To confirm that every tool is working, run this sequence in a single terminal:
free -h && uptime && df -h / && iostat -c 1 2 | tail -n 5
Expected output: three memory lines, one load average line, one root disk line and two CPU samples. If any command complains with “command not found”, review the sysstat installation.
For a more robust test, open htop in one window and in another run:
yes > /dev/null &
You should see the yes process saturating one vCPU in htop. Kill it with kill %1 in the same terminal where you launched yes.
Troubleshooting
iotop fails with “Could not run iotop as non-root user”
Even with sudo, some containerized environments deny access to the netlink taskstats interface. Use pidstat -d 1 from sysstat as an alternative — it shows I/O per process without requiring special capabilities.
vmstat and iostat show odd counters on the first line
The first line is always the average since system boot, not the current state. Ignore it and read from the second line on. That is why it is a habit to run vmstat 1 5 (5 samples) and mentally discard the first.
top shows a process using 200% CPU
Not a bug. top reports usage summed across cores, so a multithreaded process on a 4 vCPU machine can reach 400%. Press 1 to see each vCPU separately and size things correctly.
kill -9 (SIGKILL) does not allow the process to clean up open files, release locks or flush buffers. Always use kill <pid> (SIGTERM) first and wait a few seconds. SIGKILL only when SIGTERM fails — databases and processes that write to disk can corrupt data.
Next steps
Real-time monitoring covers the “now”, but intermittent issues require history. A few directions to dig deeper:
- Configure
sar(fromsysstat) for metric retention — it stores CPU, memory and disk data every 10 minutes with 30 days of history by default. - Study
atopin daemon mode (atop -w file 60) — it records full system snapshots that you can review later withatop -r file. - Learn to read
/proc/pressure/{cpu,memory,io}(PSI — Pressure Stall Information), which quantifies how much each resource is delaying processes. - For larger environments, consider a metrics system with
node_exporterexporting to Grafana — it provides graphical visualization and alerts.
If you are pushing this into production, a Hostini VPS comes with dedicated vCPUs (no aggressive oversubscription) and NVMe storage, which keeps %util and await numbers healthy even under sustained load — making diagnosis easier when something really goes off-pattern.
Frequently asked questions
What is the difference between 'free' and 'available' in the free -h command?
'free' is the completely idle memory — nothing is using it. 'available' is an estimate of how much the kernel can hand to new processes without falling back to swap, counting reclaimable cache. In production, look at 'available'; a low 'free' with a high 'available' is normal and healthy.
Why does the load average show a value higher than the number of CPUs?
Load average counts processes in runnable or uninterruptible I/O state, not just CPU. A load of 4.0 on a 2 vCPU machine can be 100% CPU saturation or stuck disk I/O. Cross-check with 'top' (%CPU vs %wa line) or 'vmstat 1' (r and b columns) to tell them apart.
iotop asks for root even with sudo configured — why?
iotop relies on taskstats from the kernel, which requires CAP_NET_ADMIN. Even via sudo, some minimal environments (containers, custom kernels) block it. Alternatives: 'pidstat -d 1' from the sysstat package or reading /proc/<pid>/io directly.
Can I leave htop running in the background to record history?
No — htop is interactive and does not log data. For history, use 'sar' (from sysstat), 'atop' in daemon mode (-w file interval), or export metrics through node_exporter. htop is for live inspection, not retention.
Linux cache is eating all my RAM, is that a problem?
No. The kernel uses idle RAM as page cache and buffers to speed up I/O — that space is reclaimed instantly when processes need it. Worry only if 'available' (not 'free') drops low and swap starts growing.
Why does df -h show a full disk but du cannot find the files?
Most likely they are deleted files still held open by processes — the inode stays allocated until the process closes the descriptor. Use 'lsof +L1' to list files with link count zero and identify the process. Restarting the owning service frees the space.