Gendi Notes

Linux Basics

Almost every server, container and cloud instance you will ever touch runs Linux — so this is the layer underneath everything else in these notes.

Level 1 guide linuxfilesystempermissionsprocesses

What is it?#

Linux is the operating system that runs the internet. When you deploy to AWS, run a Docker container, or kubectl exec into a pod, you are working on Linux.

You interact with it through a shell — usually bash or zsh — by typing commands. There is no GUI on a server.

Why it matters before anything else#

Every layer above Linux is an abstraction over it. When those abstractions leak — and they always do — you land back here:

The abstractionWhat you actually debug
"The container is out of memory"A Linux cgroup limit and the OOM killer
"The pod can't reach the service"Linux routing, DNS resolution, iptables
"The deploy hangs"A Linux process ignoring a signal
"The disk is full"Linux inodes, or a file nobody deleted properly

Learning Kubernetes before Linux is possible, but you end up memorising commands instead of understanding what they do.

What it is made of#

┌──────────────────────────────────────────────┐ │ your commands: bash, ls, curl, systemctl │ ← userspace └──────────────────────┬───────────────────────┘ │ system calls ┌──────────────────────↓───────────────────────┐ │ THE KERNEL │ │ processes · memory · filesystems · network │ └──────────────────────┬───────────────────────┘ │ drivers ┌──────────────────────↓───────────────────────┐ │ hardware / hypervisor │ └──────────────────────────────────────────────┘
PieceWhat it does
KernelManages processes, memory, devices and the network. You never call it directly
ShellReads your commands and runs them (bash, zsh)
FilesystemOne tree starting at /. Everything is a file, including devices
ProcessesEvery running program. Each has an ID (PID) and an owner
Users & permissionsWho may read, write or execute what
systemdStarts and supervises long-running services
Package managerInstalls software (apt, dnf, apk)

How to use it#

The filesystem is one tree#

There are no drive letters. Everything hangs off /:

PathHolds
/etcConfiguration files. Almost every "where do I change this?" ends here
/var/logLogs
/home/youYour files. Shortcut: ~
/usr/bin, /binInstalled programs
/tmpTemporary files, usually wiped on reboot
/proc, /sysNot real files — live kernel state exposed as files
/optManually installed third-party software
Moving around
pwd                 # where am I?
ls -lah             # list: long, all (incl. hidden), human-readable sizes
cd /var/log         # go somewhere
cd -                # jump back to the previous directory
find /etc -name "*.conf"   # find files by name

Reading files without opening an editor#

cat file.txt              # print the whole thing (small files only)
less file.txt             # page through it. q to quit, / to search
head -20 file.txt         # first 20 lines
tail -20 file.txt         # last 20 lines
tail -f /var/log/syslog   # FOLLOW a file as it grows — the log-watching command
grep -i "error" app.log   # find lines containing "error", case-insensitive
grep -rn "TODO" ./src     # recursive, with line numbers

tail -f and grep together will cover most of your log reading.

Permissions#

ls -l shows something like -rw-r--r--. Read it in four parts:

- rw- r-- r-- │ │ │ │ type owner group everyone else (rw-) (r--) (r--) r = read (4) w = write (2) x = execute (1) rw- = 4+2 = 6 r-- = 4 rwx = 7 so -rw-r--r-- is 644, -rwxr-xr-x is 755
chmod 644 file.txt      # owner can edit, everyone can read
chmod +x script.sh      # make a script runnable — the common one
chown user:group file    # change owner (needs sudo)

Processes#

ps aux                  # every process. Pipe into grep to find one
ps aux | grep nginx
top                     # live view, sorted by CPU. q to quit
htop                    # nicer top, if installed

kill <pid>              # ask politely (SIGTERM) — lets it clean up
kill -9 <pid>           # force (SIGKILL) — no cleanup. Last resort

Services with systemd#

Anything that runs continuously — nginx, PostgreSQL, Docker — is a systemd service.

sudo systemctl status nginx     # is it running? Shows recent log lines too
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx     # re-read config WITHOUT dropping connections
sudo systemctl enable nginx     # start automatically on boot
journalctl -u nginx -f          # follow this service's logs
journalctl -u nginx -n 100      # last 100 lines

systemctl status and journalctl -u <service> are the first two commands to run when a service misbehaves. status says whether it is running; journalctl says why it is not.

Disk and packages#

df -h                 # free space per filesystem
du -sh ./*            # size of each item here — finds the big directory
du -sh /var/log/*     # a very common culprit

sudo apt update              # refresh the package list (Debian/Ubuntu)
sudo apt install nginx       # install
sudo apt remove nginx        # uninstall

On RHEL, Rocky and Fedora the command is dnf instead of apt; on Alpine it is apk.

Two things that trip everyone up#

Interview corner · الأسئلة اللي بتتسأل#

What is the difference between SIGTERM and SIGKILL, and why does it matter in production?

SIGTERM (signal 15, plain kill) is a request. The process receives it and can run a handler: finish in-flight work, flush buffers, close connections, deregister from a load balancer, then exit.

SIGKILL (signal 9) is not delivered to the process at all. The kernel removes it. No handler runs, nothing is flushed.

Why it matters beyond Linux — the same two-phase shutdown is everywhere:

LayerSends SIGTERM, waits, then SIGKILL
docker stop10 seconds by default (--time)
Kubernetes30 seconds (terminationGracePeriodSeconds)
systemd90 seconds (TimeoutStopSec)

So an application that ignores SIGTERM does not shut down gracefully anywhere, and every deploy silently drops in-flight requests.

df shows 90% used. You delete a 20 GB log file. df still shows 90%. Why?

Because a process still has the file open. rm removed the directory entry, not the data.

The kernel frees an inode's blocks only when both the link count and the open-descriptor count reach zero. rm dropped the link count to zero; the descriptor is still held.

lsof +L1                   # files with link count 0 that are still open
lsof -nP | grep deleted

# Fix without a restart — truncate through the descriptor itself:
: > /proc/<pid>/fd/<fd>
A script works when you run it, and fails under sudo with "command not found". Why?

sudo does not just elevate privileges — it replaces the environment. secure_path in /etc/sudoers overrides PATH, and most environment variables are stripped unless explicitly preserved with env_keep.

So a binary in /opt/tool/bin that your shell finds via a PATH entry in your .bashrc is simply not on root's PATH.

# Prove it — compare the two
echo "$PATH"
sudo sh -c 'echo "$PATH"'

# Fixes, best first
sudo /opt/tool/bin/mytool        # full path — explicit, no surprises
sudo -i                          # a real login shell for root
sudo -E command                   # preserve YOUR environment (use with care)

Key takeaways#

  • One tree from /. Config in /etc, logs in /var/log, live kernel state in /proc.
  • tail -f and grep will handle most log reading you ever do.
  • Permissions are three groups of rwx — owner, group, everyone. 644 for files, 755 for executables, 600 for secrets. Never 777.
  • kill asks, kill -9 forces. Always ask first.
  • systemctl status then journalctl -u — the two commands for any broken service.
  • df -h for space, df -i for inodes. "Full disk" with space free means inodes.

Last updated 2026-09-08