The operating system every container, server, and CI runner actually runs on. You can't debug a crashing pod, a full disk, or a hung process without Linux fluency. This is a hands-on path from the filesystem to processes, permissions, networking, and the troubleshooting reflexes that separate juniors from on-call engineers. Work top to bottom, or jump to a part.
The journey:
| You need | Why |
|---|---|
| Access to a Linux shell | A VM, WSL, a container (docker run -it ubuntu bash), or a cloud box |
| Basic terminal comfort | Everything here is CLI |
No root-owned production box required — a throwaway container is perfect to practice on. Confirm your environment:
uname -a # kernel + architecture
cat /etc/os-release # distro and version
whoami # your current user
The shell (usually Bash) is your interface to the kernel. Linux lays everything out under a single root /:
| Path | Holds |
|---|---|
/etc |
System + service configuration |
/var |
Logs, spools, variable data (/var/log) |
/home |
User home directories |
/usr/bin, /bin |
Executables |
/tmp |
Scratch space (wiped on reboot) |
/proc, /sys |
Virtual views of kernel/process state |
pwd # where am I
ls -lah # list: long, all (incl. hidden), human sizes
cd /var/log # change directory
tree -L 2 # visual tree (if installed)
Everything in Linux is a file — including devices, sockets, and process info under /proc. Internalize that and the system stops feeling mysterious.
cat file # dump a small file
less file # page through a big one (q to quit, / to search)
head -n 20 file # first 20 lines
tail -f /var/log/app.log # follow a log live — your #1 debugging tool
cp / mv / rm # copy, move, remove (rm -r for dirs; be careful)
find / -name "*.conf" -mtime -1 # files named *.conf changed in last day
tail -f (or less +F) on a log while you reproduce a bug is the single most-used move in ops. find is your filesystem search engine — by name, size, age, or type.
Every file has an owner, a group, and three permission triples — for user/group/other — each with read (4), write (2), execute (1).
ls -l script.sh # -rwxr-xr-- 1 alice devs ...
chmod 750 script.sh # rwx for owner, r-x for group, none for other
chmod +x script.sh # make executable
chown alice:devs file # change owner and group
rwx = 7, rw- = 6, r-x = 5, r-- = 4. So chmod 644 is the classic "owner writes, everyone reads." When something "won't run" or a service "can't read its config," permissions are the first suspect. sudo runs a single command as root — use it deliberately, not reflexively.
A process is a running program with a PID. The kernel schedules them; you observe and control them.
ps aux # snapshot of all processes
top / htop # live, sorted by CPU/memory
kill <pid> # send SIGTERM (ask nicely to stop)
kill -9 <pid> # SIGKILL (force — last resort, no cleanup)
kill -HUP <pid> # often "reload config" for daemons
jobs / fg / bg / & # foreground/background control
nohup cmd & # keep running after you log out
Signals matter: SIGTERM (15) lets a process shut down cleanly (flush, close connections); SIGKILL (9) can't be caught and skips cleanup — reach for it only when TERM fails. This is exactly why Docker's CMD should use the exec form: so signals reach your process.
Linux's superpower: small tools chained with pipes (|), each doing one thing.
# How many 500s in the log, by URL, top 10?
grep ' 500 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
cat file | grep pattern # filter lines (use grep -r to search trees)
awk '{print $1, $4}' file # columns by field
sed 's/old/new/g' file # stream find-and-replace
cut -d: -f1 /etc/passwd # split on a delimiter
sort | uniq -c # count occurrences
wc -l file # count lines
xargs # turn output into arguments for another command
The pattern grep | awk | sort | uniq -c | sort -rn — "filter, extract a column, count, rank" — answers a huge fraction of real production questions. Learn it cold.
df -h # disk space per filesystem — first check on "disk full"
du -sh * # size of each item here (find what's eating space)
free -h # memory used/free/available
uptime # load averages (1/5/15 min)
vmstat 1 # CPU/memory/IO over time
lsof +D /var # what has files open under a path (find the culprit for "disk full but df/du disagree")
"Disk full" and "out of memory" are two of the most common incidents. df -h then du -sh * drilling down finds the space; free -h and the OOM killer messages in dmesg explain the memory.
ip addr # interfaces and IPs (replaces ifconfig)
ss -tulpn # listening ports + owning process (replaces netstat)
ping host # is it reachable at all?
curl -v https://host/path # make an HTTP request, see headers + timing
dig example.com # DNS resolution
traceroute host # where packets die on the way
ss -tulpn ("what's listening, on which port, owned by which process") answers "port already in use" and "is my service even up?" curl -v is how you test an endpoint from the box itself, ruling in or out DNS, TLS, and connectivity in one shot.
On modern distros, systemd starts, supervises, and logs long-running services (units).
systemctl status nginx # is it running? recent logs?
systemctl start/stop/restart nginx
systemctl enable nginx # start on boot
systemctl reload nginx # re-read config without a full restart
journalctl -u nginx -f # follow that service's logs live
journalctl -u nginx --since "10 min ago"
systemctl status + journalctl -u <svc> is the two-step you run for any "the service is down" report — status shows state and the last lines; journalctl gives the full story.
A repeatable order beats guessing. When a box misbehaves:
df -h — is a disk full? (Breaks logging, databases, everything.)free -h / dmesg | tail — out of memory? Did the OOM killer strike?top / htop — what's eating CPU or memory right now?journalctl -u <svc> -e or tail -f the log — what is the service actually saying?ss -tulpn / curl -v — is it listening and reachable?ls -l / id — permissions or ownership blocking it?Follow the evidence top-down; don't restart blindly until you know why.
rm -rf without looking. There's no undo and no trash can. Double-check the path; never run it as root on a variable you didn't verify.kill -9 first. SIGKILL skips cleanup and can corrupt state. Try SIGTERM, give it a moment, then escalate.chmod 777 to "fix" permissions. It's a security hole, not a fix. Grant the least access that works (chmod 640/750).systemctl reload/restart to pick up changes.cat. Use less, tail -f, or journalctl — and check whether logs rotated.$? (0 = success) tells you if the last command actually worked; scripts must check it.df and du agree. A deleted-but-open file eats space du can't see — use lsof to find it.docker run -it ubuntu bash), explore /etc, /var/log, and /proc. Find the 5 largest files under /var with find/du.chmod.sleep 1000 &, find it with ps/top, send it SIGTERM, then start another and SIGKILL it. Note the difference.grep | awk | sort | uniq -c | sort -rn | head).systemctl status, follow its logs with journalctl -f, then confirm it's listening with ss -tulpn.Self-check:
chmod 640 grant?You now have the core loop: navigate → inspect → control processes → read logs → check resources → fix. That's the daily reality of running systems.
Learned the concepts? Test yourself with Linux interview questions.
Go to the question bank →