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.
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 abstraction | What 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#
| Piece | What it does |
|---|---|
| Kernel | Manages processes, memory, devices and the network. You never call it directly |
| Shell | Reads your commands and runs them (bash, zsh) |
| Filesystem | One tree starting at /. Everything is a file, including devices |
| Processes | Every running program. Each has an ID (PID) and an owner |
| Users & permissions | Who may read, write or execute what |
| systemd | Starts and supervises long-running services |
| Package manager | Installs software (apt, dnf, apk) |
How to use it#
The filesystem is one tree#
There are no drive letters. Everything hangs off /:
| Path | Holds |
|---|---|
/etc | Configuration files. Almost every "where do I change this?" ends here |
/var/log | Logs |
/home/you | Your files. Shortcut: ~ |
/usr/bin, /bin | Installed programs |
/tmp | Temporary files, usually wiped on reboot |
/proc, /sys | Not real files — live kernel state exposed as files |
/opt | Manually installed third-party software |
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 nameReading 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 numberstail -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:
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 resortkill does not mean killPlain kill sends SIGTERM, a request to shut down that the program can handle: finish the current request, flush data, exit cleanly.
kill -9 sends SIGKILL, which cannot be caught. Nothing is flushed and no cleanup runs — so a database killed this way may need recovery on restart.
Always try kill first. Reach for -9 only when the process is genuinely stuck.
kill و kill -9 مهم أكتر مما تتخيلاسم الأمر مضلّل. kill مش معناها اقتل.
kill بيقول للبرنامج «لو سمحت اقفل» — والبرنامج بيقدر يمسك الإشارة دي، يخلّص اللي في إيده، يحفظ، ويقفل بالراحة. دي SIGTERM.
kill -9 بيقول للكيرنل «شيله» — والبرنامج مش بيعرف حتى إنه بيموت. مفيش حفظ، مفيش تنظيف، مفيش قفل كونيكشنز. دي SIGKILL ومحدش يقدر يتجاهلها.
وعشان كده: لو عملت kill -9 لداتابيز، ممكن تلاقيها محتاجة recovery لما تقوم تاني، وممكن تخسر آخر حاجات اتكتبت.
القاعدة: اطلب بالذوق الأول. kill -9 آخر حاجة، ولما البرنامج يكون معلّق فعلاً ومش بيرد.
docker stop بيبعت SIGTERM، بيستنى ١٠ ثواني، وبعدين SIGKILL. وكوبرنيتيس بيعمل نفس الحاجة بالظبط بس بـ ٣٠ ثانية (terminationGracePeriodSeconds).
يعني الحكاية اللي إنت بتتعلمها هنا في لينكس، هي هي اللي بتشتغل فوق في كل الطبقات. عشان كده بنبدأ من هنا.
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 linessystemctl 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.
أي حاجة شغالة على طول على السيرفر — nginx، بوستجرس، دوكر نفسه — دي بتبقى systemd service.
ولما حاجة منهم تبوظ، فيه أمرين بس بتبدأ بيهم، بالترتيب ده:
يعني: status بيقولك هو عايش ولا مات. و journalctl بيقولك مات ليه.
وأهم فرق لازم تعرفه في الشغل:
| الأمر | بيعمل إيه | الكونيكشنز |
|---|---|---|
restart | بيقتل العملية ويشغّل واحدة جديدة | بتقع كلها |
reload | بيقول للعملية «اقرا الإعدادات تاني» | بتكمل عادي |
فلو إنت على سيرفر ويب في البرودكشن وغيّرت إعداد، reload الأول. اللي بيعمل restart على طول بيقطع على كل اللي بيستخدمو الموقع في اللحظة دي — وده مش لازم، عشان nginx بيعرف يعيد قراءة إعداداته وهو شغّال.
بس خد بالك، مش كل سيرفيس بيدعم reload. لو مش مدعوم، systemctl status هيقولك إن الطلب اتجاهل.
reload versus restartrestart stops the process and starts a new one — connections drop. reload tells the running process to re-read its configuration and keep serving.
For a web server in production, always try reload first. Not every service supports it; systemctl status will tell you if it was ignored.
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 # uninstallOn RHEL, Rocky and Fedora the command is dnf instead of apt; on Alpine it is apk.
Two things that trip everyone up#
df -h shows 40% used, but writes still fail. The disk is not full — the inodes are. Each file consumes one inode regardless of size, so millions of tiny files exhaust the table while using little space.
df -i # inode usage. IUse% at 100% is your answerUsual cause: a directory full of session files, cache entries or unrotated logs. Delete the files, then fix whatever created them.
sudo changes the environment, not just the permissionssudo command runs as root with a different PATH and environment. A script that works for you can fail under sudo with "command not found", and sudo echo $HOME prints your home because your shell expanded it before sudo ran.
Use sudo -i for an interactive root shell, or give commands their full path.
١. «مفيش مساحة» والمساحة فاضية
df -h بيقولك ٤٠٪ مستخدم، ومع ذلك مش قادر تكتب أي ملف. إيه الحكاية؟
الديسك مش فضي — الـ inodes هي اللي فضيت.
كل ملف بياخد inode واحدة، مهما كان حجمه. ملف فيه حرف واحد بياخد inode، وملف ٢ جيجا بياخد inode. والجدول ده له عدد محدود.
فلو عندك مليون ملف صغير (session files، كاش، لوجز مش بتتلف)، الجدول خلص وإنت لسه معندكش داتا تقريباً.
df -i # بصّ على عمود IUse% — لو ١٠٠٪ يبقى دي هيالحل: امسح الملفات، وبعدين ظبّط الحاجة اللي بتعملهم — عشان لو ما ظبطتهاش هترجعلك تاني بعد أسبوع.
٢. sudo مش بس بيغيّر الصلاحيات، بيغيّر البيئة كلها
sudo command بيشتغل كـ root وبـ PATH مختلف ومتغيرات مختلفة.
فسكريبت شغّال معاك تمام، تحت sudo يقولك command not found. مش عشان الصلاحيات — عشان الـ root معندهوش نفس الـ PATH بتاعك.
وفيه حاجة أظرف: sudo echo $HOME بتطبع الـ home بتاعك إنت، مش بتاع الروت. ليه؟ عشان الشِل بتاعك فكّ $HOME قبل ما sudo يشتغل أصلاً.
الحل: sudo -i عشان تاخد شِل روت حقيقي، أو اكتب المسار الكامل للأمر.
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:
| Layer | Sends SIGTERM, waits, then SIGKILL |
|---|---|
docker stop | 10 seconds by default (--time) |
| Kubernetes | 30 seconds (terminationGracePeriodSeconds) |
| systemd | 90 seconds (TimeoutStopSec) |
So an application that ignores SIGTERM does not shut down gracefully anywhere, and every deploy silently drops in-flight requests.
SIGTERM (رقم ١٥، وهو اللي kill بيبعته) هو طلب. البرنامج بيستلمه ويقدر يعمل handler: يخلّص الشغل اللي في إيده، يكتب اللي في الرام على الديسك، يقفل الكونيكشنز، يشيل نفسه من الـ load balancer، وبعدين يموت.
SIGKILL (رقم ٩) مش بيوصل للبرنامج خالص. الكيرنل بيشيله. مفيش handler بيشتغل ومفيش أي حاجة بتتحفظ.
وليه ده مهم أكتر من لينكس؟ عشان نفس الميكانيزم موجود في كل طبقة فوق:
| الطبقة | بتبعت SIGTERM، تستنى، وبعدين SIGKILL |
|---|---|
docker stop | ١٠ ثواني |
| كوبرنيتيس | ٣٠ ثانية |
| systemd | ٩٠ ثانية |
يعني برنامج مش بيسمع SIGTERM مش بيقفل بالراحة في أي مكان، وكل ديبلوي بيقطع على الريكوستات اللي كانت شغالة — من غير ما حد يلاحظ.
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>This is why log rotation configs use copytruncate, or send the service a SIGHUP to reopen its files. A rotation script that just rms the old log leaks the space until the service happens to restart — which on a stable service can be months.
عشان فيه عملية لسه ماسكة الملف مفتوح. rm شال الاسم، مشالش الداتا.
الكيرنل بيفك بلوكات الملف بس لما الاتنين يبقوا صفر: عدد الأسماء اللي بتشاور عليه، وعدد العمليات اللي فاتحاه. rm صفّر الأول، والتاني لسه واحد.
lsof +L1 # الملفات اللي اتمسحت ولسه مفتوحة
: > /proc/<pid>/fd/<fd> # تفضّيه من غير ريستارتوالدرس الهندسي: عشان كده إعدادات لف اللوجز بتستخدم copytruncate، أو بتبعت SIGHUP للسيرفيس عشان يفتح ملفاته من جديد.
سكريبت بيعمل rm للوج القديم وبس، بيسرّب المساحة لحد ما السيرفيس يحصله ريستارت بالصدفة — وده على سيرفيس مستقر ممكن يبقى بعد شهور.
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)sudo echo $HOME prints your home directory, and sudo echo x > /root/f fails with permission denied. In both cases your shell expanded the variable and opened the redirect before sudo ran — the elevation applies only to echo. Use sudo sh -c 'echo x > /root/f'.
sudo مش بس بيرفع صلاحياتك — بيستبدل البيئة كلها.
فيه إعداد اسمه secure_path في /etc/sudoers بيلغي الـ PATH بتاعك، وأغلب المتغيرات بتتشال إلا لو حد سمح بيها بالاسم.
فبرنامج موجود في /opt/tool/bin وإنت ضايفه في الـ PATH بتاعك من .bashrc، ببساطة مش موجود في PATH بتاع الروت.
اتأكد بنفسك: echo "$PATH" وبعدها sudo sh -c 'echo "$PATH"' وقارن.
والحلول بالترتيب: اكتب المسار الكامل، أو sudo -i تاخد شِل روت حقيقي، أو sudo -E تحافظ على بيئتك (بس خد بالك دي فيها مخاطر أمنية).
والفخ اللي جنبه: sudo echo x > /root/f بيفشل. ليه؟ عشان الشِل بتاعك فتح الـ redirect قبل ما sudo يشتغل — فالصلاحية اتطبّقت على echo بس. الصح: sudo sh -c 'echo x > /root/f'.
Key takeaways#
- One tree from
/. Config in/etc, logs in/var/log, live kernel state in/proc. tail -fandgrepwill handle most log reading you ever do.- Permissions are three groups of
rwx— owner, group, everyone.644for files,755for executables,600for secrets. Never777. killasks,kill -9forces. Always ask first.systemctl statusthenjournalctl -u— the two commands for any broken service.df -hfor space,df -ifor inodes. "Full disk" with space free means inodes.
- شجرة واحدة من
/. الإعدادات في/etc، اللوجز في/var/log، وحالة الكيرنل الحية في/proc. tail -fوgrepهيعملولك أغلب قراءة اللوجز اللي هتعملها في حياتك.- الصلاحيات تلات مجموعات
rwx— الصاحب، الجروب، الباقي. ٦٤٤ للملفات، ٧٥٥ للسكريبتات، ٦٠٠ للسري. ومتكتبش ٧٧٧ خالص. killبيطلب، وkill -9بيفرض. اطلب الأول دايماً.systemctl statusوبعدهاjournalctl -u— الأمرين لأي سيرفيس باظ. الأول بيقولك عايش ولا مات، والتاني بيقولك مات ليه.df -hللمساحة، وdf -iللـ inodes. «ديسك فضي» والمساحة موجودة يعني الـ inodes خلصت.reloadقبلrestartعلى أي حاجة في البرودكشن. الأول بيحافظ على الكونيكشنز، والتاني بيقطعها.
Last updated 2026-09-08