I opened today's session with a question.
"Imagine you leave your laptop open in a coffee shop in Westlands. What stops a stranger from reading your files?"
Silence. A few answers. Then I said: "On Linux - the answer is permissions. Every single file on this server has a set of rules that says who can touch it. Today we are going to learn exactly how that works, live on a real server."
New cohort. Fresh faces. Some had never touched a terminal before. By the end of two hours, they had created real user accounts, organised them into groups, locked down files, and proved - by trying to break in as a different user -that their permissions actually worked.
Here's how it went.
First: Getting On a Real Server
No local files. No virtual machines. We SSH'd into a live Ubuntu server.
ssh root@159.x.x.x
That first SSH fingerprint warning - the one that looks scary - causes a pause in every cohort:
The authenticity of host '159.x.x.x' can't be established.
Are you sure you want to continue connecting (yes/no)?
I explained: "Linux is asking - I've never seen this server before, do you trust it? We say yes." After that, the prompt changed:
Welcome to Ubuntu 22.04 LTS
root@server:~#
That # symbol. I made sure everyone understood what it meant - root, the most powerful user on the system. The whole reason permissions exist is to protect files from that kind of power being used carelessly.
The Mental Model: Three Questions Linux Always Asks
Before any commands, I drew three questions on the board:
- WHO owns this file? - the Owner
- What GROUP is it in? -the Group, a shared team of users
- Is everyone else allowed? - Others
And for each of those three, Linux grants up to three abilities:
| Symbol | Name | On a file | On a directory |
|---|---|---|---|
r |
read | Open and read it | Run ls inside |
w |
write | Edit or delete it | Create/delete files inside |
x |
execute | Run it as a program |
cd into it |
- |
none | Denied | Denied |
Then the 10-character string that wraps all of this together:
- r w x r - x r - -
───── ───── ─────
owner group others
└── file type: - = file, d = directory
Five minutes of theory. Then hands-on immediately.
Creating Real Users: Alice and Bob
We created two users directly on the server - alice and bob. These would be our test subjects for the whole session.
adduser alice
Linux walked through everything interactively - set a password, created a home folder at /home/alice, created a group with the same name. I made the point: "Notice Linux did several things at once. It created the user, created a private group for her, and gave her a home folder that belongs to her alone."
id alice
uid=1001(alice) gid=1001(alice) groups=1001(alice)
Three ways to verify a user exists - id, checking /etc/passwd, and listing /home/. I showed all three so students knew different tools rather than memorising one path.
Groups: The Company Department Analogy
The real-world analogy I use every time: a company. Everyone in the Development team can read the source code. Everyone in Finance can read payroll files. You don't set permissions for every individual - you create a group and add people to it.
groupadd devteam
usermod -aG devteam alice
usermod -aG devteam bob
groups alice
alice : alice devteam
The -aG warning always needs emphasis. Use -G without -a and you silently remove all the user's existing groups. One missing letter, broken access. I've seen that mistake cause real problems in production environments. Worth saying twice in class.
Reading Permissions: The ls -l Moment
We created a /project folder with three files:
mkdir /project
echo 'This is the main app code' > /project/app.py
echo 'Top secret salary data' > /project/salaries.txt
echo 'Public readme' > /project/README.txt
ls -l /project/
-rw-r--r-- 1 root root 26 Jan 1 10:00 app.py
-rw-r--r-- 1 root root 24 Jan 1 10:00 README.txt
-rw-r--r-- 1 root root 23 Jan 1 10:00 salaries.txt
All three files showing -rw-r--r--. I pointed at salaries.txt and said: "Right now, any user on this server can read the salary file. That's a problem. Let's fix it."
chmod: Locking Things Down
Two ways to use chmod - numbers (fast) and symbols (readable). I teach both.
The number system: each permission has a value. r=4, w=2, x=1. Add them up for each group. Owner, group, others — three digits.
The numbers worth memorising:
| Number | String | Use |
|---|---|---|
777 |
rwxrwxrwx |
Everyone everything — dangerous |
755 |
rwxr-xr-x |
Programs, public directories |
644 |
rw-r--r-- |
Normal files |
640 |
rw-r----- |
Team files — group reads, others locked |
600 |
rw------- |
Private (SSH keys, credentials) |
We set them live:
chmod 600 /project/salaries.txt
chmod 640 /project/app.py
chmod 644 /project/README.txt
ls -l /project/
-rw-r--r-- 1 root root 24 Jan 1 10:00 README.txt
-rw-r----- 1 root root 26 Jan 1 10:00 app.py
-rw------- 1 root root 23 Jan 1 10:00 salaries.txt
The Moment That Made the Session
Then we switched to alice and tried to read the salary file:
su - alice
cat /project/salaries.txt
cat: /project/salaries.txt: Permission denied
The room reacted. A few people laughed. One student said "it actually works."
That's the moment I wait for every cohort. Not because it's complicated — it isn't. But because seeing a real system refuse access, because of rules they set, makes it concrete in a way no amount of theory can. They didn't just learn about permissions. They used them.
chown: Handing Ownership to the Right Person
Permissions control what can be done. Ownership controls who the rules apply to. chown transfers ownership:
chown alice:devteam /project/app.py
ls -l /project/app.py
-rwxr----- 1 alice devteam 26 Jan 1 10:00 app.py
Now alice owns the file and devteam is the group. Because bob is in devteam, the group permission (r--) applies to him - he can read, but not write.
We proved it:
su - bob
cat /project/app.py # works - group has r
echo 'bob was here' >> /project/app.py # denied - group has no w
This is the main app code
bash: /project/app.py: Permission denied
"Bob can read the code but can't change it. That's how a real team works."
What I Noticed Teaching This Session
1. The SSH fingerprint warning catches everyone. It looks dangerous. A quick calm explanation - "Linux is asking if you trust this server" - is all it takes. Don't skip it.
2. The Permission denied moment is worth engineering. I could have just explained that permissions work. Instead I made them set up a file, lock it down, then try to break in as another user. Seeing their own rules enforced is the most memorable minute of the session.
3. The -aG warning needs to be said out loud, twice. Silent data loss - user loses all group memberships with one wrong flag - is the kind of mistake that causes real incidents. Beginners need to hear that this is serious before they learn the command, not after.
4. New cohort energy is different. These students had never touched a terminal before today. By the end they were switching between user accounts, testing access, reading permission strings without help. That progression in two hours is why I love this job.
Try It Yourself
You don't need a paid server. Spin up a free Ubuntu instance on:
- Oracle Cloud Free Tier — always free, real Ubuntu server
- WSL2 — Windows Subsystem for Linux, runs locally
Then run through the sequence: create two users, a group, three files with different permissions, and prove it works by switching between accounts. The Permission denied message will feel like a win, not an error.
I'm a data trainer in Nairobi running a full data programme -
Python foundations → Data Science or Data Engineering specialisations.
I write daily about what I taught, what worked, and what surprised me in the classroom.
Follow along or drop your questions in the comments.

Top comments (0)