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

The troubleshooting checklist: Ten questions, in order. No guessing.

"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

#QuestionCommand
1Is it reachable at all?ping 192.168.1.50 from your laptop
2Can I log in?ssh john@192.168.1.50
3Is the server actually up and sane?uptime · systemctl --failed
4Is anything full?df -h · df -i · free -h
5Is something hogging it?htop · docker stats
6Is the service running and listening?systemctl status x · docker ps · sudo ss -tlnp
7Is the firewall in the way?sudo ufw status
8What changed?last reboot · `grep -h " install | upgrade " /var/log/dpkg.logtail · journalctl --since "1 day ago" _COMM=sudo`
9What do the logs say?journalctl -u x -n 100 · docker compose logs --tail 100 · journalctl -p err -b
10Can 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.

Call us