Page 1 of 2
Most modern Linux distributions manage services through systemd, an init system - the first process the kernel starts at boot, responsible for starting, stopping, and supervising everything else.
systemctl status nginx # is it running, and what has it logged recently?
systemctl start nginx # start it now
systemctl stop nginx # stop it now
systemctl restart nginx # stop then start
systemctl enable nginx # start it automatically on every future boot
A common confusion: start/stop control the service right now, while enable/disable control whether it launches automatically on boot. You can enable a service without starting it (it'll come up next reboot but isn't running yet), or start one without enabling it (running now, but won't survive a reboot). Forgetting enable after start is a classic cause of "it worked, then the server rebooted and it was gone."
For processes you launch yourself rather than through systemd:
long-running-task & # & backgrounds the job, returns your shell prompt immediately
nohup long-running-task & # nohup means the task survives you closing the terminal
jobs # list background jobs in this shell session
fg %1 # bring job 1 back to the foreground
Without nohup, a backgrounded job is still tied to your terminal session - close the SSH connection and it dies too (it receives a SIGHUP, "hangup" signal). nohup tells it to ignore that signal.
"The disk is full" is one of the most common production incidents, and diagnosing it has a standard toolkit.
df -h # disk free, per filesystem, human-readable sizes
du -sh /var/log # disk used by this directory, summarized, human-readable
du -sh /var/log/* # same, but broken out per item inside - find the culprit
lsblk # list block devices (physical/virtual disks and their partitions)
mount # show what's currently mounted where
A genuinely common trap: df says a filesystem is full, but you delete a huge file and df still shows it full. This happens when a running process still has that file open - Linux doesn't actually free the disk space until every process holding it closes it, even after it's unlinked from the directory listing. The fix is usually to restart or signal the process holding it open (lsof | grep deleted can find these), not to keep deleting more files that won't help.
Logs are where you go first for almost every investigation. Traditionally, services wrote plain text logs under /var/log:
tail -f /var/log/nginx/access.log # -f follows the file live as new lines are written
On systemd-based systems, many services instead log through journald, queried with journalctl:
journalctl -u nginx # logs for just the nginx unit
journalctl -u nginx -f # follow nginx's logs live
journalctl --since "1 hour ago" # time-bounded window
journalctl -p err # only error-priority and above
Knowing whether a service logs to a flat file, to journald, or both is genuinely important - if you're staring at an empty log file wondering why nothing's there, checking journalctl -u <service> before assuming the service is silent will save you real time.
Beyond ping and curl, real troubleshooting needs to answer "what's actually listening, and what's actually happening on the wire."
ss -tulnp # show listening TCP/UDP sockets, with the process using each one
dig example.com # query DNS directly, see exactly what it resolves to
traceroute example.com # show the network hops between you and a destination
ss (socket statistics, the modern replacement for the older netstat) is usually your first stop when something "isn't reachable" - it tells you definitively whether a process is actually listening on the port you expect, and on which interface. A service bound to 127.0.0.1 instead of 0.0.0.0 will work perfectly from the same machine and be completely unreachable from anywhere else - a very common source of "it works locally but not from outside" confusion.
A basic firewall with ufw (Uncomplicated Firewall, a friendlier front-end over the kernel's real firewall):
sudo ufw allow 22/tcp # allow SSH
sudo ufw allow 443/tcp # allow HTTPS
sudo ufw enable # turn the firewall on
grep, sed, and awk are the backbone of quickly slicing text on the command line, especially logs.
grep "ERROR" app.log # print lines containing "ERROR"
grep -i "error" app.log # -i = case-insensitive
grep -c "ERROR" app.log # -c = count matching lines instead of printing them
grep -v "DEBUG" app.log # -v = invert match, show lines NOT containing this
sed 's/foo/bar/' file.txt # substitute the first "foo" with "bar" on each line
sed -i 's/foo/bar/g' file.txt # -i edits the file in place, /g replaces every match per line
awk '{print $1}' access.log # print just the first whitespace-separated field of each line
These three overlap in confusing ways for beginners: grep finds lines, sed transforms text within lines, awk is closer to a full mini-language for structured columns of data. A rough rule of thumb - reach for grep to filter, sed for simple find-and-replace, awk once you're dealing with columns of data rather than whole lines.
Real scenario-based DevOps questions, hands-on practice, and clear explanations for every answer.