Experienced admins don’t know every error message, but they follow a method. Random guessing (“let’s restart everything”) sometimes works, but it hides the cause, and the problem comes back. This guide gives you a repeatable process that works for slow websites, crashing services, network problems, and everything in between.
1. Define the problem precisely
Turn “the server is broken” into facts:
- What exactly fails? (One page? All sites? SSH? Email?)
- For whom? (Everyone, one country, one user, only logged-in users?)
- Since when? Exact time, if possible.
- Error messages: copy them exactly.
- Is it constant or intermittent?
A precise description often points straight at the layer that’s failing.
2. Ask: what changed?
Most incidents follow a change:
grep -E " install | upgrade " /var/log/dpkg.log | tail -20 # package changes
sudo git -C /etc log --since "2 days ago" --stat # if you use etckeeper
last -a | head # who logged in
journalctl --since "2 hours ago" -p warning
Deployments, config edits, package updates, certificate expiry, DNS changes, traffic spikes, and full disks are the usual suspects. See etckeeper and check login history.
3. Check resources quickly (the USE method)
For each resource (CPU, memory, disk, network), check Utilisation, Saturation and Errors:
| Resource | Utilisation | Saturation | Errors |
|---|---|---|---|
| CPU | top, mpstat |
Load average > vCPUs, run queue (vmstat r) |
— |
| Memory | free -h |
Swapping (vmstat si/so), OOM kills |
journalctl -k | grep -i oom |
| Disk | df -h, iostat -x |
await, I/O wait (wa) |
dmesg I/O errors |
| Network | iftop, vnstat |
Drops, retransmits (ss -s, nstat) |
ip -s link errors |
Two minutes of this rules out (or finds) the most common causes. See VPS performance troubleshooting and uptime and load average.
4. Read the logs
systemctl --failed
systemctl status <service>
journalctl -u <service> --since "30 min ago"
sudo tail -n 100 /var/log/nginx/error.log
The answer is usually written there, often one or two lines before the obvious error. See Linux log files explained and journalctl.
5. Isolate the layer
Work from the outside in (or the inside out), and test each layer directly:
DNS → network path → firewall → web server → app/PHP → database → disk
dig +short example.com # DNS
mtr -rwc 20 example.com # network path
curl -sI http://127.0.0.1 -H 'Host: example.com' # web server locally, bypassing DNS/CDN
ss -tlnp | grep -E ':80|:443|:3306' # are services listening?
mysql -e 'SELECT 1' # database
If it works locally but not remotely, it’s the firewall, DNS, or the network. If it fails locally too, it’s the service itself. See network troubleshooting.
6. Form a hypothesis, test one change at a time
- Change one thing, test, and observe.
- Prefer reversible changes (a config backup,
nginx -tbefore reload). - If it didn’t help, revert it before trying the next idea.
7. Fix the cause, not just the symptom
Restarting a crashed service restores it, but why did it crash? Memory leak? Full disk? Bad input? Add monitoring or limits, so you’ll know (or prevent it) next time. See Linux cgroups and Uptime Kuma.
8. Document
Write a short note: symptom, cause, fix, and prevention. It helps the next person (often future you), and builds your runbooks. See Linux disaster recovery plan.
When you can’t reach the server at all
Use the VNC console in your VPS control panel. It works even when SSH, the firewall, or the network config is broken. Check the client area for the server’s status, and contact support if the host or network seems affected. See VPS VNC console.
Quick reference
| Step | Key commands |
|---|---|
| What changed? | dpkg.log, git -C /etc log, last |
| Resources | top, free -h, df -h, iostat -x, vmstat 1 |
| Failed services | systemctl --failed |
| Logs | journalctl -u svc, app error logs |
| Isolate | dig, mtr, curl to 127.0.0.1, ss -tlnp |
| Change safely | One change, test, revert if no effect |
Related: Linux server hardening checklist and eBPF basics.