Monitoring a VDS starts not with external alerting services, but with basic console utilities that are already on the system or install with a single package. They are enough to tell within a minute exactly what is slowing the server down: CPU, memory, disk, or network.
Basic VDS Monitoring
The usual diagnostic order is: first the overall load picture (uptime, htop), then narrowing down to the specific bottleneck subsystem.
# Average load over 1, 5, and 15 minutes
uptime
The three numbers in the uptime output are the load average. If the first number (over the last minute) is noticeably higher than the server's CPU core count, the system is overloaded right now; if all three keep climbing, the load has been sustained for a while rather than being a one-off spike.
CPU Load and Processes
htop # interactive monitor with sorting and a process tree
top # standard monitor, available everywhere with no install
ps aux --sort=-%cpu | head -10 # top 10 processes by CPU
RAM Usage
free -h # human-readable output: total, used, free, available
free -m # the same in megabytes, handy for scripts
The available column, not free, shows the real memory reserve: Linux actively uses free RAM for the file cache, so a low free value alongside a high available value is normal, not a sign of memory shortage.
Disk Space
df -h # free space per partition
du -sh /var/www # size of a specific directory
du -sh /var/www/* | sort -rh | head -10 # top heaviest subdirectories
Network Connections
netstat -tulpn # open ports and listening processes (an aging tool)
ss -tulpn # a modern replacement for netstat, faster on servers with thousands of connections
ss -s # summary socket statistics
Error Logs
tail -f /var/log/nginx/error.log
tail -f /var/log/syslog
journalctl -u nginx -n 50 --no-pager # for systems with systemd-journal
Common Scenarios Explained
Load average above the core count, while CPU sits nearly idle in htop is a classic sign of disk wait (I/O wait) rather than CPU load. Watch the wa column in top's output: if it is high, the bottleneck is the disk, not the processor, and it is not fixed by a CPU upgrade.
The kernel message Out of memory: Killed process 1234 (mysqld) in dmesg means the OOM killer forcibly terminated the process due to insufficient memory. Find this with dmesg | grep -i "killed process" — after such an event it is worth checking whether it is time to add swap or cap the service's memory, rather than just restarting it.
A port is listening but unreachable from outside — ss -tulpn shows the bind address: if a service listens on 127.0.0.1:8080 rather than 0.0.0.0:8080, it will not answer from outside regardless of firewall settings. This is a frequent cause of "the service seems to be running, but the site does not open."
Comparing Monitoring Tools
| Tool | What it shows | Format | When to use it |
|---|---|---|---|
| top / htop | CPU, RAM, processes in real time | Interactive, in the terminal | Quick diagnosis right now |
| vmstat / dstat | CPU, memory, I/O, swap in one line | Periodic output | Tracking a trend over minutes |
| Logs (tail, journalctl) | Application and system errors | Text stream | Understanding the cause, not just the symptom |
| Netdata / Grafana+Prometheus | Metric history with graphs | Web interface, data storage | Long-term trends, alerts |
If console utilities are not enough and you need graphs going back weeks along with alerts sent to a messenger, the next step is deploying Netdata or a Grafana and Prometheus setup.
When Console Monitoring Is Not Enough
- You need metric history from past weeks, not just the current snapshot —
topandfreeremember nothing once the terminal is closed. - You need automatic alerts when a threshold is crossed (for example, disk filled to 90%) — console utilities cannot send alerts on their own.
- There is more than one server, and you need a single dashboard — checking a separate SSH terminal for each VDS stops scaling after 3–4 servers.
- You need profiling at the level of individual application requests (APM), not just system resources — that is a separate class of tools built on top of basic monitoring.
Verifying the Result
- Get the basic picture with one command:
uptime && free -h && df -h— if all three numbers are healthy, there is no acute resource problem. - Make sure the ports you need are listening on the right address:
ss -tulpn | grep LISTEN. - Check that the logs are not clogged with old, repeated errors — that is also disk load and a sign of an unresolved problem.
- If you plan to monitor on an ongoing basis, set up autostart for the chosen tool via systemd and check it survives a server reboot.
For a deeper look at CPU, disk, and memory diagnostics with process-level profiling, see the article on Linux performance profiling.