Linux Server Troubleshooting Checklist (What to Check, in Order, When Something's Wrong)

"The server isn't working" is where every problem starts, and the fastest way through is the same every time: narrow it down in a fixed order rather than guessing. This is the order. Each step is a command or two from earlier in the series; most problems reveal themselves by step 5.
The checklist
| # | Question | Command | |
|---|---|---|---|
| 1 | Is it reachable at all? | ping 192.168.1.50 from your laptop | |
| 2 | Can I log in? | ssh john@192.168.1.50 | |
| 3 | Is the server actually up and sane? | uptime · systemctl --failed | |
| 4 | Is anything full? | df -h · df -i · free -h | |
| 5 | Is something hogging it? | htop · docker stats | |
| 6 | Is the service running and listening? | systemctl status x · docker ps · sudo ss -tlnp | |
| 7 | Is the firewall in the way? | sudo ufw status | |
| 8 | What changed? | last reboot · `grep -h " install | upgrade " /var/log/dpkg.log | tail · journalctl --since "1 day ago" _COMM=sudo` |
| 9 | What do the logs say? | journalctl -u x -n 100 · docker compose logs --tail 100 · journalctl -p err -b | |
| 10 | Can I reproduce it while watching? | journalctl -f in one window, trigger it in another |
1. Reachable?
ping 192.168.1.50
No reply: it's off, the network is down, or the IP changed (router's device list, or the screen on the server). Reply: the machine is alive; the problem is higher up.
2. Can you log in?
SSH works → skip ahead. Connection refused → SSH itself is down (console, tutorial 37). Hangs → the server is overloaded or the disk is full; try again in a minute, then console. Permission denied → keys/Fail2ban (tutorials 3, 7).
3. Up and sane?
uptime
systemctl --failed
An uptime of three minutes means it rebooted — power cut, unattended-upgrades, or a crash: journalctl -b -1 -p err for the previous boot's errors. --failed lists crashed services by name, which often is the answer.
4. Anything full?
df -h
df -i
free -h
A disk or inode table at 100% causes every strange symptom there is — databases stopping, logins failing, "cannot allocate memory" errors. Tutorial 15. Memory with no available and swap in heavy use: tutorial 16.
5. Hogging?
htop
docker stats --no-stream
A single process at 100% CPU or a container at its memory limit. Kill it (tutorial 17), limit it (tutorial 68), or just wait for the backup to finish.
6. Is the service up and listening?
systemctl status nginx
docker ps
sudo ss -tlnp | grep :8096
Running but not listening on the expected port means a config error (nginx -t) or it's bound to 127.0.0.1 only. Not running: journalctl -u name says why it stopped.
7. The firewall
sudo ufw status numbered
Works on the server (curl http://localhost:8096) but not from your laptop → firewall or the bind address. Remember Docker publishes ports past UFW, so "works from outside but shouldn't" is also a firewall question.
8. What changed?
Servers don't break spontaneously. Something was updated, edited, filled up or rebooted:
last reboot | head -3
grep -h " install \| upgrade " /var/log/dpkg.log | tail -20
journalctl --since "2 days ago" _COMM=sudo | grep -v session | tail -20
ls -lt /etc/nginx/sites-enabled/ ~/docker/*/compose.yaml | head
The last thing that changed is the first suspect.
9. The logs
journalctl -u name -n 100 --no-pager
docker compose logs --tail 100 name
journalctl -p err -b --no-pager | tail -30
sudo tail -50 /var/log/nginx/error.log
Read from the bottom up. The first error, not the last, is the cause; the rest are consequences.
10. Reproduce it while watching
journalctl -f
in one window (or docker compose logs -f), then do the thing that fails in another. The log line that appears at that instant is the one that matters.
Asking for help
If you post on a forum, include: the Ubuntu version (lsb_release -ds), what you expected, what happened instead, the exact error text (not a photo), the relevant 20 lines of log, what changed recently, and what you've already tried. A question with those gets answered; "it doesn't work" doesn't. Strip passwords and public IPs before pasting (tutorial 59 habits help here).
The five-minute version
uptime; systemctl --failed; df -h | grep -v tmpfs; free -h; docker ps --format '{{.Names}}\t{{.Status}}'; journalctl -p err -b --no-pager | tail -15
Paste that into an alias (alias check='...' in ~/.bashrc) and run it first, every time.
Wrapping up
Reachable, loggable, up, full, hogging, listening, firewall, changed, logs, watch. Ten steps, in order, with no guessing. Most problems fall out at step 3, 4 or 8, and the ones that don't leave you with exactly the information someone else needs to help.
