The site won't come up. You SSH in, log in, and now you have ten minutes to figure out whether the problem is CPU, disk, the web service, or DNS. This article is exactly that path: Linux commands in the order they're actually run, not in alphabetical order.
Before anything else, one rule: run every command you see here on a test server first, not on production. Some of these only read and are harmless; one or two are not.
First look at the server, not the site
When the site is slow or timing out, the first number you should look at is load average:
uptime
# 14:32:07 up 41 days, 3:12, 2 users, load average: 12.40, 9.85, 4.20
The last three numbers are the average load over the past one, five, and fifteen minutes. Rule of thumb: if this number exceeds the number of CPU cores, a queue has formed. Check the core count with nproc. A load of 12 on a 4-core server means three times capacity; a load of 12 on a 16-core server means you still have room.
An important point: does high load always mean CPU is maxed out? No. If load is high but top shows CPU is idle, the problem is disk I/O. This is where people make mistakes: the site admin sees load has gone up, upgrades the server, and the problem — which was slow network disk — stays right where it was.
top -o %CPU
free -h
df -h
df -i
Read free -h carefully. The available column is what matters, not free. Linux spends free memory on cache and that's normal; if available gets close to zero and swap is full, then you have a memory problem. df -h shows disk space and df -i shows inode count. A "No space left on device" error while df -h says 40% is free almost always means inodes are exhausted — usually because of millions of small session or cache files.
Which process is eating the disk
To see the top consumers by memory and CPU:
ps aux --sort=-%mem | head -n 10
ps aux --sort=-%cpu | head -n 10
And to figure out which process is actually generating disk I/O, install iotop (the iotop package is in the standard repos). If iotop isn't available, vmstat 1 is enough: if the si and so columns show large numbers, the system is swapping, and that's the worst case for a web server.
One trade-off I should state plainly: killing a process with kill -9 is the fastest way and I do it myself in emergencies, but if the process is a database, it can corrupt tables and you'll face a recovery error after restart. Send kill -15 first, wait ten seconds, then if it doesn't respond, -9.
Web service and ports
If the site isn't responding at all, before anything else check whether the web service is alive:
systemctl status nginx
systemctl status apache2
systemctl status php8.2-fpm
And then the ports:
ss -tulpn | grep -E ':80|:443|:3306'
If port 80 isn't listening, the problem is at the service layer, not in the site's code. If it is listening but you get no response from outside, it's probably a firewall or Cloudflare in the middle. ss is the successor to netstat; on newer distros netstat may not even be installed.
To test the HTTP response from the server itself, without DNS in the way:
curl -I -H "Host: example.com" http://127.0.0.1
curl -o /dev/null -s -w "%{time_total}\n" https://example.com
The second number is the total request time in seconds. If this number is under 0.5 and users are still complaining, the problem isn't your server; it's the network path or DNS. Breaking down status codes like 502 and 504 is covered in the HTTP status code guide and is exactly what you need at this stage.
Logs: where the real answer is
No command replaces reading logs. Paths differ by distro:
tail -f /var/log/nginx/error.log
tail -n 200 /var/log/nginx/access.log
journalctl -u php8.2-fpm --since "30 min ago"
journalctl -xe
In the access log, look for 500 codes and see which path repeats the most:
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
If a specific IP is hammering the server, you'll find it right there. If the 500 error is concentrated on a specific script, the problem is a plugin or code, not the server. For WordPress sites, auditing plugins usually gets results faster than any server tuning.
A practical warning: tail -f on a log that produces thousands of lines per second can itself lock up your terminal. For high volume, use grep with a filter, not raw watching.
Network, DNS, and database connection
When the site responds from inside the server but not from outside, the test order is:
dig +short example.com A
dig +trace example.com
ping -c 4 8.8.8.8
mtr -rw example.com
dig +trace shows the full resolve path and if it breaks somewhere, it's clear right there. An NXDOMAIN error means the record doesn't exist or the zone didn't load correctly; details on diagnosing it are in the DNS_PROBE_FINISHED_NXDOMAIN error.
For the database, test two things separately: network connectivity and authentication connectivity.
mysql -h 127.0.0.1 -u appuser -p -e "SELECT 1;"
mysqladmin -u root -p status
If mysqladmin status shows Threads_connected close to the max_connections ceiling, the problem is here: web requests sit behind the connection queue and the site slows down, without CPU or disk having any issue. This is one of those cases where everyone looks at the web server and the database is the culprit.
A few commands that save time
du -sh /var/log/* | sort -h— finding fat logs that have filled the disk.lsof -i :80— which process has taken the port.find /var/www -name "*.php" -mtime -1— which files have changed in the past 24 hours; for tracking a suspicious change.crontab -landls /etc/cron.d/— a backup or script that puts the server to sleep at 3 AM.last -n 20— recent logins; if you see an unknown IP, change passwords first, then troubleshoot.
On WordPress, if you have SSH access, WP-CLI is several times faster than the panel: wp plugin list --status=active and wp cron event list show in seconds what's running in the background. If WordPress cron is stuck, the site becomes slow on every visit; the diagnostic pattern is explained in the wp-cron problem.
When these steps aren't enough
If after all of this load is low, the disk is healthy, there's no error in the logs, but the site is still slow, the problem is probably at the platform layer: storage network, container CPU quota, or a noisy neighbor on a virtual host. At this point Linux commands won't help and you need to contact the provider. If you're on shared hosting or WordPress hosting, this is exactly the point where opening a ticket makes more sense than flailing around in the terminal.
For day-to-day work, a small script that writes uptime, free -h, and df -h to a file every five minutes will serve you better than any expensive tool. When the site goes down, having a history of these three numbers over the past two hours is the difference between guessing and diagnosing. More ready-made tools are available in free tools and step-by-step guides in the documentation.
Frequently asked questions
How do I tell whether the problem is CPU or disk?
If load average is high but top shows a large portion of CPU is idle (id), the bottleneck is disk. With vmstat 1, look at the wa column; a number above 20 percent means processes are waiting on I/O. In this case, upgrading CPU won't help at all.
What's the difference between kill -15 and kill -9, and which should I use?
kill -15 sends a clean termination request and the process has a chance to close files and connections. kill -9 kills immediately with no chance and for a database can cause a long recovery. Always 15 first, and if the process is still there after ten seconds, 9.
Why does df say there's space but I get a No space left on device error?
Because inodes are exhausted, not space. Check with df -i. The common cause is a mass of small files: PHP sessions, cache files, or a mail queue. Finding them starts with find /path -type f | wc -l on the suspect directories.
The site opens from inside the server but not from outside; where do I start?
First check DNS with dig +short example.com A and see whether the returned IP is the server's IP. Then check the firewall and open ports with ss -tulpn. If both are correct, there's probably a proxy or CDN in the middle and you need to check that layer's settings.
Comments 0
No comments yet — be the first!