1. Courses
  2. Engineering Roles
  3. TechOps: Linux, Networks and IT Operations
  4. Stop 1

40 minBeginner

Linux from the command line

Every Mangrove store has a small Linux server in the back office, and when it struggles, the tills and scanners feel it. This lesson teaches you to log in safely, find your way around, read the signs in processes, disk, services and logs, and fix common problems without creating new ones.

By the end you can

  • Log in to a store box with an SSH key and turn password logins off without locking yourself out
  • Find configuration, logs and app data, and read them with less, tail and grep
  • Read and set permissions with chmod and chown, and explain why 777 is never the fix
  • Check processes, load and disk, and stop a process with the right signal
  • Start, enable and debug a service with systemctl and journalctl

The everyday picture

Picture the back room of a store. Shelves have fixed places: deliveries here, paperwork there, cleaning things in the corner. Keys decide who opens what: the manager has a master key, a cashier has a key to the cash room only, and anyone who borrows the master key signs the book. Staff on shift each do one job, and a shift supervisor makes sure the night stock-taker turns up and finds a replacement when someone walks out. Every worker writes what happened in the logbook.

A Linux server is the same room. The folders are the shelves, users and permissions are the keys, sudo is borrowing the master key, processes are the staff, systemd is the supervisor, and the logs are the logbook. When the store feels slow, a good manager does not shout at everyone. She reads the logbook, looks at who is busy, and checks whether the back room is full. You will do exactly that, with commands.

Getting in and finding your way

Each store has a store box: a small server running Ubuntu Server 24.04 LTS. It caches prices for the scanners, queues till sales when the internet drops, and runs the receipt print service. It has no screen. You reach it over the store's VPN with , using its hostname, such as store-0142. If cd, ls and pipes are new to you, do The terminal without fear first; this lesson builds on it.

Log in with a , not a password. A password can be guessed, reused or passed around in a chat group. A private key cannot be guessed, and each person's public key is one line in their ~/.ssh/authorized_keys file on the box, so removing one person removes one line.

Terminal
# On your laptop, once: make a key pair (choose a passphrase when asked)
ssh-keygen -t ed25519 -C "nadia@techops-laptop"
# Copy the public key to the box (asks for your password one last time)
ssh-copy-id nadia@store-0142
# From now on, the key logs you in
ssh nadia@store-0142

Once keys work for everyone who needs access, switch passwords off. Ubuntu's main SSH config, /etc/ssh/sshd_config, reads the files in /etc/ssh/sshd_config.d/ first, and the SSH server uses the first value it finds for each setting. So put your rules in a file whose name sorts early:

Output
# /etc/ssh/sshd_config.d/10-keys-only.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
Terminal
sudo sshd -t                                        # test the config: no output means it is valid
sudo sshd -T | grep -i '^passwordauthentication'    # the value the server will really use
sudo systemctl reload ssh                           # on Ubuntu the unit is called ssh, not sshd
Output
passwordauthentication no

Once you are in, everything has a fixed place. Linux puts every disk under one tree that starts at /, the root. These are the folders you will use every day:

FolderWhat lives thereOn a store box
/etcConfiguration, as plain text files/etc/mangrove/pricecache.env, /etc/ssh/
/var/logLog files/var/log/mangrove/, /var/log/syslog
/var/libData programs keep between restarts/var/lib/mangrove/tillqueue/: queued till sales
/homeEach person's own folder/home/nadia
/optSoftware installed outside the package manager/opt/mangrove/: the price cache and till queue programs
/tmpScratch space; may be emptied at rebootNever keep anything here you need

To read files, use three tools. less is a : it opens a file of any size instantly, / searches, n jumps to the next match, G goes to the end and q quits. tail shows the end of a file, and tail -f keeps printing new lines as they arrive, which is how you watch a till upload happen live. grep prints only the lines that contain a word.

Terminal
less /var/log/mangrove/tillqueue.log                          # page through; /word searches, q quits
tail -n 20 /var/log/mangrove/tillqueue.log                    # the last 20 lines
tail -F /var/log/mangrove/tillqueue.log                       # follow new lines, even after the log is rotated; Ctrl+C stops
grep -c "upload failed" /var/log/mangrove/tillqueue.log       # count matching lines
grep -i "timeout" /var/log/mangrove/tillqueue.log | tail -n 5 # last 5 matches, any upper or lower case

Users, groups and permissions

Every process runs as a user, and every file has an owner (a user) and a group. A group is a named set of users, such as techops. The id command tells you who you are:

Output
uid=1001(nadia) gid=1001(nadia) groups=1001(nadia),4(adm),27(sudo),1005(techops)

On Ubuntu, the sudo group may run commands as root, and the adm group may read most logs. Services get their own : the price cache runs as pricecache and the till queue as tillqueue, so a bug in one cannot overwrite the other's files. You create one with sudo useradd --system --no-create-home --shell /usr/sbin/nologin tillqueue.

ls -l shows the permissions:

Output
-rwxr-x--- 1 root techops 2210 Oct  2 10:15 flush-queue.sh
-rw-r----- 1 root techops  512 Oct  2 10:15 stores.conf
drwxr-x--- 2 root techops 4096 Oct  2 10:15 reports

The first character is the type: - for a file, d for a directory. The next nine are three groups of three: what the owner may do, what members of the group may do, and what everyone else may do. r is read, w is write, x is execute, and - means no. So flush-queue.sh can be read, changed and run by root, read and run by the techops group, and nobody else may touch it.

On a directory the letters mean something different. r lets you list the names inside, x lets you enter it and open files by name, and w (together with x) lets you create, rename and delete files in it. Deleting a file depends on the folder's permissions, not the file's.

Each group of three is often written as one digit: r = 4, w = 2, x = 1, added up. rwx is 7, r-x is 5, rw- is 6, r-- is 4. So rwxr-x--- is 750 and rw-r----- is 640. Common modes: 755 for programs everyone may run, 644 for files everyone may read, 640 for logs, 600 for secrets and SSH files. The SSH server refuses your key if your .ssh folder or authorized_keys file can be written by other users.

Terminal
sudo chown root:techops /opt/mangrove/tools/flush-queue.sh   # owner root, group techops
sudo chmod 750 /opt/mangrove/tools/flush-queue.sh            # rwx owner, r-x group, nothing for others
chmod 600 ~/.ssh/authorized_keys                             # only you may read or change it
sudo chmod g+r /var/log/mangrove/tillqueue.log               # add read for the group, change nothing else
sudo usermod -aG adm ops-trainee                             # add a user to a group (-a keeps the old groups)

A group change takes effect at the user's next login, so the new member logs out and in again. When Linux decides whether you may open a file, it checks in a fixed order and stops at the first match, as the diagram shows.

pricecache.log 640 owner pricecache group adm 1. Are you root? yes may read, write no 2. Are you the owner? yes owner bits rw- no 3. In group adm? yes group bits r-- no 4. Everyone else other bits --- First match wins
Linux uses only one set of bits. An owner whose bits say no is refused, even if the group bits would allow it. Root skips the read and write checks entirely, which is why root must be used with care.

Now you can see why chmod 777 is never the fix for "Permission denied". It gives write access to every account on the box: the print service, any program with a bug, and any attacker who breaks into one of them. If a script with mode 777 is run by root, anyone who can edit it can run commands as root. The right fix is to find who needs access (ls -l on the file, id for the user) and give exactly that: change the owner, or add the user to the group.

sudo runs one command as root and writes it to the log, with your name. Use it per command. Avoid staying in a root shell with sudo -i for routine work: one wrong rm in the wrong folder has no safety net.

Quick check

/opt/mangrove/tools/flush-queue.sh has mode 750, owner root, group techops. A member of techops who is not root runs nano flush-queue.sh and tries to save a change. What happens?

Processes, signals and load

A is a running program, and each has a number, its PID. ps takes a snapshot of them; top shows a live view that refreshes every few seconds (press M to sort by memory, P by CPU, q to quit). htop is a friendlier version, if it is installed (sudo apt install htop).

Terminal
ps -eo pid,user,stat,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 3   # busiest processes first
Output
    PID USER     STAT %CPU %MEM     ELAPSED CMD
   1187 priceca+ Ssl   3.1 10.2 12-03:11:40 /opt/mangrove/pricecache/bin/pricecache
    912 tillque+ Ssl   0.4  2.1 12-03:11:42 /opt/mangrove/tillqueue/bin/tillqueue

Long user names are cut short with a +, so priceca+ is the pricecache account. The STAT column's first letter is the state. R is running or ready to run, S is sleeping (waiting for work, which is normal), D is waiting for the disk or another device and cannot be interrupted, Z is a zombie (finished, but its parent has not collected it). Many D processes mean the disk is the bottleneck.

uptime and the first line of top show the : three numbers for the last 1, 5 and 15 minutes. Compare them with the number of CPUs, which nproc prints. On a 4-CPU box, a load of about 4 means the CPUs are roughly fully used; 9 means tasks are queuing. On Linux, the load also counts tasks stuck in state D, so a high load with idle CPUs points at the disk, not the CPU. In top, the wa value (time the CPUs sat waiting for disk) confirms it.

To stop a process you send it a . The ones you need:

  • TERM (15): "please stop". The default for kill PID. The program can catch it, finish what it is doing and save its data.
  • INT (2): what Ctrl+C sends to the program in front of you.
  • HUP (1): many server programs reload their config when they get it. This depends on the program, so check its documentation.
  • KILL (9): "stop now". The program cannot catch it. The kernel ends it at once, with no clean-up and no saving.

Mangrove's till queue holds the last few sales in memory and writes them to disk when it gets TERM. A kill -9 skips that step. So for anything run as a service, do not use kill at all: use systemctl stop or systemctl restart. systemd sends TERM, waits (90 seconds by default), and sends KILL only if the program is still running. A process in state D often cannot be killed even with -9 until the disk answers.

Quick check

The till queue on store-0142 stopped uploading sales and does not answer its health check. What is the safest way to stop it?

Services with systemd, logs with journalctl

starts every service on the box, watches it, and restarts it if it dies. Each service is described by a . Packages install theirs in /usr/lib/systemd/system/; your own go in /etc/systemd/system/. This is the till queue's:

INI
# /etc/systemd/system/mangrove-tillqueue.service
# (systemd allows comments only on their own lines, never after a value)
[Unit]
Description=Mangrove till sales queue
# start once the network is up
Wants=network-online.target
After=network-online.target

[Service]
# run as the service account, never as root
User=tillqueue
Group=tillqueue
EnvironmentFile=/etc/mangrove/tillqueue.env
ExecStart=/opt/mangrove/tillqueue/bin/tillqueue
# if it exits with an error, start it again after 5 seconds
Restart=on-failure
RestartSec=5

[Install]
# what "enable" hooks it into: the normal boot
WantedBy=multi-user.target

You drive it with systemctl. start runs a service now; enable makes it start at every boot. They are separate, and forgetting enable is the classic reason a service "disappears" after a reboot. After you edit a unit file, run sudo systemctl daemon-reload so systemd reads the new version. To change a packaged unit, use sudo systemctl edit NAME: it saves your changes in a separate override file that survives package updates, and reloads for you.

Terminal
systemctl status mangrove-tillqueue               # running? since when? main PID, last log lines
sudo systemctl restart mangrove-tillqueue         # stop (TERM, then KILL if needed), then start
sudo systemctl enable --now mangrove-tillqueue    # start at boot, and start now
systemctl --failed                                # every unit that has failed
systemctl cat mangrove-tillqueue                  # the unit file plus any overrides
tillqueue.service boot systemctl start if enabled systemd (PID 1) 1. start as tillqueue 3. again after 5 s 2. crashes exit code 1 tillqueue (PID 912) stdout, stderr journald one journal for every service journalctl -u you, over SSH
systemd starts the service as its own user, at boot if it is enabled. When the program exits with an error, Restart=on-failure starts it again after RestartSec. Everything the program prints goes to journald, and journalctl -u shows one service's share of it.

Everything a service prints, plus systemd's own notes about starts, stops and crashes, goes to the . journalctl reads it, and its filters are what make it useful. On Ubuntu, members of the adm group can read the whole journal; others need sudo.

Terminal
journalctl -u mangrove-tillqueue --since "07:00"     # one service, from 07:00 today
journalctl -u mangrove-tillqueue --since "2026-10-19 22:00" --until "2026-10-20 06:00"
journalctl -u mangrove-tillqueue -f                  # follow new lines, like tail -f
journalctl -p err --since today                      # only errors, from every service
journalctl -b -1 -n 50                               # last 50 lines of the previous boot
journalctl --disk-usage                              # how much space the journal takes

-b -1 works only if the journal is kept on disk (the folder /var/log/journal exists). Some programs, like the price cache, also write their own log file under /var/log/mangrove/. Check both: the journal tells you when the service started, stopped or crashed, and the app's log tells you what it was doing.

Quick check

On Friday you installed a new print helper service and ran sudo systemctl start mangrove-printhelper. It worked. After Monday's power cut, it is not running, and systemctl status says inactive (dead) with no errors. What was missed?

Disk space: df, du and the file that will not go away

A full disk breaks things in strange ways: the till queue cannot save sales, logins fail, services crash with No space left on device. Two commands find the cause. df -h shows each and how full it is. du adds up the size of folders, so you can walk down to the one that grew.

Terminal
df -h                                                  # how full is each filesystem?
sudo du -xh --max-depth=1 /var | sort -h | tail -n 5   # the biggest folders in /var
sudo du -h /var/log/* | sort -h | tail -n 5            # then go one level deeper

-h prints sizes like 41G instead of byte counts, -x stays on one filesystem so du does not wander into other disks, and sort -h sorts those human sizes correctly. Work top-down: the biggest folder, then the biggest inside it, until you find the file. If df shows free space but you still get "No space left", run df -i: the disk may have run out of because something made millions of tiny files.

There is one trap everybody meets once. When you rm a file that a running process still has open, the name disappears but the space is not freed until the process closes it. du no longer sees the file, df still counts it, and the two disagree. Restarting the service frees the space. To empty a log a service is still writing, use sudo truncate -s 0 FILE instead of rm.

uptime load 9.1 on 4 CPUs tasks are queuing who is busy? top wa 64%: disk wait pricecache in state D disk full? df -h / is 98% full only 1.2G left what grew? du -xh /var /var/log is 41G one file: pricecache.log since when? journalctl -u debug on since 16:10 set in a support call Fix: level back to info, empty log, restart
Each command answers one question and points to the next. Write down what each one showed: those notes become the ticket, and they are the evidence a reboot would have destroyed.

Build it

We will replay the store-0142 investigation command by command, fix it without losing evidence, and check that the fix held.

  1. Log in and get the big picture

    Log in with your key, then compare the load with the CPU count.

    Terminal
    ssh nadia@store-0142
    uptime
    nproc
    Output
     08:42:15 up 12 days,  3:11,  1 user,  load average: 9.12, 8.47, 6.30
    4

    A load of 9 on 4 CPUs, and still rising (the 1-minute number is the highest). Something is queuing. Do not reboot: you would lose the evidence.

  2. See who is busy, and on what

    Run top and read the header before the process list.

    Output
    top - 08:42:31 up 12 days,  3:11,  1 user,  load average: 9.05, 8.46, 6.31
    Tasks: 141 total,   2 running, 139 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 14.2 us,  9.8 sy,  0.0 ni, 11.6 id, 64.1 wa,  0.0 hi,  0.3 si,  0.0 st
    MiB Mem :   3916.2 total,    212.4 free,   1408.9 used,   2294.9 buff/cache
    
        PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
       1187 priceca+  20   0 1254300 422500  18200 D  38.0  10.5 161:12.34 pricecache
        912 tillque+  20   0  402116  88300  12100 D   4.1   2.2  12:40.02 tillqueue

    The CPUs spend 64% of their time waiting for the disk (wa), and the two Mangrove processes are in state D. This is a disk problem, not a CPU problem. Memory looks fine: most of it is cache that Linux gives back when needed.

  3. Check the disks and find what grew

    Terminal
    df -h /
    sudo du -xh --max-depth=1 /var | sort -h | tail -n 3
    sudo ls -lh /var/log/mangrove/
    Output
    Filesystem                         Size  Used Avail Use% Mounted on
    /dev/mapper/ubuntu--vg-ubuntu--lv   58G   54G  1.2G  98% /
    2.3G	/var/lib
    41G	/var/log
    45G	/var
    total 41G
    -rw-r----- 1 pricecache adm  41G Oct 20 08:42 pricecache.log
    -rw-r----- 1 tillqueue  adm  12M Oct 20 08:42 tillqueue.log

    One file holds 41 GB. Look at what is in it:

    Terminal
    sudo tail -n 3 /var/log/mangrove/pricecache.log
    Output
    2026-10-20T08:42:40.118Z DEBUG lookup sku=4006381 store=0142 hit=true 0.4ms
    2026-10-20T08:42:40.118Z DEBUG lookup sku=8901030 store=0142 hit=true 0.3ms
    2026-10-20T08:42:40.119Z DEBUG cache stats entries=24912 bytes=88112640
  4. Find what changed, and when

    The journal records every start of the service. The config file shows the setting.

    Terminal
    journalctl -u mangrove-pricecache --since yesterday | grep -i "log level"
    grep -n LOG_LEVEL /etc/mangrove/pricecache.env
    Output
    Oct 19 16:10:03 store-0142 pricecache[1187]: starting, log level debug
    4:LOG_LEVEL=debug

    Debug logging since 16:10 yesterday. Nobody changed anything today, which is exactly why Ama could not have known.

  5. Fix it without losing the evidence

    Keep a small sample for the ticket, set the level back, and empty the log while the service is stopped. The scanners' price checks pause for the few seconds the restart takes.

    Terminal
    # 1. keep the last 1,000 lines as evidence, compressed, in your home folder
    sudo tail -n 1000 /var/log/mangrove/pricecache.log | gzip > ~/pricecache-debug-sample.log.gz
    # 2. set the log level back to info, and check the change
    sudo sed -i 's/^LOG_LEVEL=debug$/LOG_LEVEL=info/' /etc/mangrove/pricecache.env
    grep -n LOG_LEVEL /etc/mangrove/pricecache.env
    # 3. stop, empty the log in place (not rm), start again
    sudo systemctl stop mangrove-pricecache
    sudo truncate -s 0 /var/log/mangrove/pricecache.log
    sudo systemctl start mangrove-pricecache
  6. Verify, then write it up

    Terminal
    systemctl status mangrove-pricecache --no-pager | head -n 3
    df -h /
    uptime          # run again after a few minutes; the 1-minute load drops first
    Output
    ● mangrove-pricecache.service - Mangrove price cache
         Loaded: loaded (/etc/systemd/system/mangrove-pricecache.service; enabled; preset: enabled)
         Active: active (running) since Tue 2026-10-20 08:51:12 UTC; 4min ago
    Filesystem                         Size  Used Avail Use% Mounted on
    /dev/mapper/ubuntu--vg-ubuntu--lv   58G   13G   43G  23% /
     08:55:40 up 12 days,  3:24,  1 user,  load average: 0.61, 3.02, 4.88

    Ask Ama to try a price check. Then write the ticket: the symptom, each command and what it showed, the cause, the fix, and two follow-ups (log rotation for the price cache, and a disk alert at 85% on every box). The commands you typed are the ticket's best part, because the next person can run them too.

Bring it to your team

Ask these in your next TechOps review of the store boxes.

  • "Who can log in to the store boxes today, and with which key? Can we remove one person from all 320 in one step?"
  • "Is password login off on every box? How would we know if one was switched back on?"
  • "Is every Mangrove program run by systemd as its own service account, enabled, with Restart=on-failure?"
  • "Which alert fires before a disk fills up, at what percentage, and who receives it?"
  • "When someone turns on debug logging, who turns it off, and when?"

Red flags

  • One shared login or password for many boxes
  • chmod 777 or chmod -R as the answer to "Permission denied"
  • kill -9 as the first step, or a reboot before anyone has read the logs
  • rm on a large log that a running service is still writing
  • Programs started by hand in a terminal instead of from a systemd unit
  • Hand edits on one box with no ticket, so the next engineer cannot tell what changed

Practice

Turn permission letters into octal

Write modeToOctal(perm). It takes the nine permission letters from ls -l (without the type character), such as 'rwxr-x---', and returns the octal mode as a three-character string, such as '750'. r = 4, w = 2, x = 1, and - = 0, added up for each group of three. Keep leading zeros: '---------' is '000'.

JavaScript exerciseRuns in your browser with tests
function modeToOctal(perm) {
  // perm is 9 letters: owner (0-2), group (3-5), others (6-8)
  // each group of three becomes one digit: r = 4, w = 2, x = 1
  return '';
}
Ctrl + Enter runs
Show a solution
JavaScript
function modeToOctal(perm) {
  const value = { r: 4, w: 2, x: 1, '-': 0 };
  let out = '';
  for (let i = 0; i < 9; i += 3) {          // owner, group, others
    let digit = 0;
    for (const ch of perm.slice(i, i + 3)) digit += value[ch];
    out += String(digit);                    // build a string, so '000' stays '000'
  }
  return out;
}
Pass the exercise to finish this task.

Decide who may read a log

Write canRead(file, user), following the order in the first diagram. file looks like { owner: 'pricecache', group: 'adm', mode: 'rw-r-----' } and user like { name: 'nadia', groups: ['nadia', 'adm', 'sudo'] }. Root may always read. Otherwise use only the owner letters (positions 0 to 2) if the user is the owner, else only the group letters (3 to 5) if the user is in the file's group, else only the last three. Return true if the chosen set has an r. The starter says yes whenever anyone may read, which is wrong.

JavaScript exerciseRuns in your browser with tests
function canRead(file, user) {
  // wrong: says yes if any of the three sets has an r
  return file.mode.includes('r');
}
Ctrl + Enter runs
Show a solution
JavaScript
function canRead(file, user) {
  if (user.name === 'root') return true;                 // root skips read checks
  let set;
  if (user.name === file.owner) set = file.mode.slice(0, 3);            // owner first
  else if (user.groups.includes(file.group)) set = file.mode.slice(3, 6); // then group
  else set = file.mode.slice(6, 9);                                      // then others
  return set[0] === 'r';                                 // first match wins: no fallback
}

The last test is the one people get wrong: an owner whose letters say no is refused, even though the group and everyone else may read.

Pass the exercise to finish this task.

Fix the till queue that keeps restarting

On store-0217, the till queue stopped uploading sales after a colleague "cleaned up" /var/lib/mangrove last night. You see this:

Output
systemctl status mangrove-tillqueue
     Active: activating (auto-restart) (Result: exit-code) since Tue 2026-10-20 09:14:55 UTC; 3s ago

journalctl -u mangrove-tillqueue -n 2
Oct 20 09:14:55 store-0217 tillqueue[20931]: open /var/lib/mangrove/tillqueue/queue.db: permission denied
Oct 20 09:14:55 store-0217 systemd[1]: mangrove-tillqueue.service: Main process exited, code=exited, status=1/FAILURE

ls -ld /var/lib/mangrove/tillqueue
drwxr-xr-x 2 root root 4096 Oct 19 23:40 /var/lib/mangrove/tillqueue

Write what is happening, the commands you run next (in order), the fix, and how you check it worked.

  • You explain that systemd keeps restarting the service (Restart=on-failure) and it fails each time on the same permission error
  • You confirm which user the service runs as (systemctl cat shows User=tillqueue) before changing anything
  • Your fix gives ownership back to the service account with chown, and does not use chmod 777
  • You check the files inside the folder too (ls -l), since queue.db may also be owned by root now
  • You verify: status shows active (running), the journal shows uploads, and queued sales go out
Show a model answer

The folder now belongs to root with mode 755, so the tillqueue user can read it but cannot write queue.db. The program exits with status 1, and Restart=on-failure starts it again every 5 seconds, failing the same way each time. Sales stay on the tills until it works again.

Terminal
systemctl cat mangrove-tillqueue | grep -E '^(User|Group)='   # confirm: tillqueue
sudo ls -l /var/lib/mangrove/tillqueue                         # is queue.db root-owned too?
sudo chown -R tillqueue:tillqueue /var/lib/mangrove/tillqueue  # give it back, folder and files
sudo systemctl restart mangrove-tillqueue
systemctl status mangrove-tillqueue --no-pager | head -n 3     # expect: active (running)
journalctl -u mangrove-tillqueue -f                            # watch the queued sales upload

In the ticket, record what the clean-up changed and ask for a rule: nobody runs chown -R or chmod -R under /var/lib/mangrove without a change ticket.

Check yourself

An hour ago a colleague ran sudo rm /var/log/mangrove/pricecache.log to free 30 GB on store-0310. df -h still shows the disk at 97%, and du cannot find the space anywhere. What is going on, and what frees the space?

A new TechOps trainee gets "Permission denied" on /var/log/mangrove/tillqueue.log, which is -rw-r----- tillqueue adm. What is the right fix?

A store box with 4 CPUs shows load average: 6.20, 6.05, 5.90. top says 78.0 id (idle) and 18.5 wa. What should you investigate first?

Flashcards

Open my review

Key takeaways

  • Log in with SSH keys and personal accounts; turn password logins off, and keep a session open while you change SSH settings.
  • Config lives in /etc, logs in /var/log, app data in /var/lib, Mangrove's programs in /opt. Read them with less, tail -F and grep.
  • Permissions are owner, group, others, checked in that order with the first match winning. Fix access with chown or group membership, never chmod 777.
  • Compare load with nproc, and check wa: Linux load includes tasks waiting for the disk. Stop services with systemctl, which sends TERM before KILL.
  • systemd runs and restarts services; enable makes them survive a reboot. journalctl -u, --since and -f tell you what happened and when.

Sources

Episode transcriptThe store box that felt slow · about 12 minutes · tap any line to play from there
  1. NadiaImran, picture a Tuesday morning. Ama calls from her store. Price checks on the scanners take five seconds instead of one, and the receipts print slowly. Nobody changed anything today. What do you do?
  2. ImranMy first instinct is to ask someone to turn the store server off and on again.
  3. NadiaThat's most people's instinct. And it often makes the problem disappear for a day, and takes every clue with it. Today we learn to look before we restart.
  4. ImranSo this is about the little Linux server in every store. The store box.
  5. NadiaRight. Each of our three hundred and twenty stores has one. It runs Ubuntu Server, it caches prices for the scanners, it queues till sales when the internet drops, and it runs the receipt printing. It has no screen. You reach it over the network from a terminal.
  6. ImranWhich sounds scary if you've never done it.
  7. NadiaSo think of the back room of a store. Shelves with fixed places. Keys that decide who opens which door. Staff on shift, each doing one job. A shift supervisor who calls a replacement when someone walks out. And a logbook where everyone writes what happened.
  8. ImranAnd the server has all of those?
  9. NadiaAll of them. Folders are the shelves, users and permissions are the keys, processes are the staff, a program called systemd is the supervisor, and the logs are the logbook. When the store feels slow, a good manager reads the logbook, sees who is busy, and checks if the back room is full. We do that with commands.
  10. ImranStart with the front door, then. How do I get in?
  11. NadiaWith SSH, which gives you an encrypted command line on another machine. And you log in with a key, not a password. A key pair is two files. The private one never leaves your laptop. The public one is a single line in a file on the box.
  12. ImranWhy does that matter so much?
  13. NadiaBecause when we first looked, every box had the same login and the same password, written in an old wiki. When a contractor left, changing it meant touching three hundred and twenty boxes, and the new password was in a chat group within a week.
  14. ImranAnd with keys, removing one person means deleting one line.
  15. NadiaExactly. Then you switch password logins off in the SSH settings. One habit saves you here: keep your current session open, log in again from a second window, and only close the first one when the new login works.
  16. ImranBecause if I break the SSH settings and close my only session, someone drives to the store.
  17. NadiaThat's the one. Once you're in, things have fixed places. Configuration lives in the etc folder, as plain text. Logs live under var, in the log folder. Data a program keeps between restarts, like the queued till sales, lives under var lib. And our own programs live in the opt folder.
  18. ImranAnd to read a log I open it in an editor?
  19. NadiaBetter not, they can be huge. Use less, which pages through any size of file and lets you search. Use tail to see the last lines, and tail with the follow option to watch new lines arrive live. And grep to print only the lines with a word in them.
  20. ImranNow the keys. Permissions always confuse me. R, w, x, and then numbers like seven five zero.
  21. NadiaEvery file has an owner and a group. There are three sets of permission letters: one for the owner, one for the group, one for everyone else. R is read, w is write, x is run. Turn each set into a digit: read is four, write is two, run is one, and you add them up.
  22. ImranSo read and write for the owner is six, read only for the group is four, nothing for others is zero. Six four zero.
  23. NadiaPerfect. That's a typical log file. Now the trap. If the price cache account owns a file and its owner letters say no, can it read the file because the group letters say yes?
  24. ImranI'd guess yes. It gets the best of the three.
  25. NadiaThat's the common guess, and it's wrong. If you can see the screen, the first diagram is a ladder of questions. If not, picture four questions, top to bottom: are you root, are you the owner, are you in the group, or are you everyone else. Linux stops at the first yes and uses only that set of letters.
  26. ImranFirst match wins. No falling through.
  27. NadiaAnd that's why the practice section has you write a small function that makes exactly that decision. The owner test is the one people get wrong.
  28. ImranWhat about when someone gets permission denied and the quick fix is chmod seven seven seven?
  29. NadiaNever. Seven seven seven means every account on the box can change the file, including any buggy program and anyone who breaks into one. If root runs that file, whoever edits it can act as root. The real fix is to give exactly the access needed, usually by changing the owner or adding the person to the group.
  30. ImranAnd they log out and back in, because a new group only applies at the next login.
  31. NadiaYou've done this before, Imran.
  32. ImranOnly the painful way. Okay, the staff. Processes.
  33. NadiaEvery running program is a process with a number. The top command shows them live, and the first line shows the load average: three numbers for the last one, five and fifteen minutes. Compare them with the number of CPUs. On a four CPU box, a load around four means the CPUs are roughly full.
  34. ImranSo a load of nine means the CPUs are overloaded.
  35. NadiaMaybe. Here's the Linux twist. The load also counts tasks stuck waiting for the disk. So a high load with idle CPUs points at the disk. In top, a value called w a, the time spent waiting for disk, tells you which it is.
  36. ImranAnd when a process is stuck, I kill it.
  37. NadiaCarefully. A plain kill sends a polite signal called TERM, please stop. The program can save its work first. Kill dash nine sends KILL, which ends it at once, no saving. Our till queue holds the last few sales in memory and writes them out on TERM.
  38. ImranSo kill dash nine could lose sales.
  39. NadiaIt could. For a service, skip kill entirely and ask systemd to stop or restart it. It sends TERM, waits, ninety seconds by default, and only then forces it.
  40. ImranTell me more about systemd, the supervisor.
  41. NadiaThe second diagram shows it. Picture a column of boxes. At the top, a small text file called a unit file. It says which program to run, as which user, and what to do if it fails.
  42. ImranAnd systemd follows those instructions.
  43. NadiaYes. It starts the till queue as its own account. If the program crashes, the unit file says restart on failure, so systemd starts it again after five seconds.
  44. ImranAnd the bottom of the column?
  45. NadiaEverything the program prints goes into the journal, one log store for every service. A command called journalctl reads it. You filter by service, by time with since and until, and you can follow it live.
  46. ImranI've heard of start and enable. Same thing?
  47. NadiaNo, and that's a classic trap. Start runs the service now. Enable makes it start at every boot. If you only start it, it's gone after the next power cut, and the status shows no error at all, because nothing crashed.
  48. ImranLast shelf: the disk.
  49. NadiaTwo commands. d f with the human option shows how full each disk is. d u adds up folder sizes, so you walk down from the biggest folder to the file that grew.
  50. ImranAnd then I delete the big file.
  51. NadiaThat's the trap everybody meets once. If a running program still has the file open, deleting it removes the name but not the space. d u can't see it any more, d f still counts it. The space comes back when that program restarts. To empty a log that's still being written, truncate it instead.
  52. ImranSo back to Ama's store. What did we actually find?
  53. NadiaThe afternoon before, a support engineer switched the price cache to debug logging to chase a price mismatch, and never switched it back. It wrote thousands of lines a second. By morning the log was forty-one gigabytes, the disk was ninety-eight percent full, and every price lookup was waiting for the disk.
  54. ImranWhich is why Ama said nobody changed anything today. The change was yesterday.
  55. NadiaRight. The third diagram shows our path: each command answers a question that leads to the next. Uptime said load nine on four CPUs. Top said sixty-four percent disk wait. d f said the main disk was full. d u found the log folder. And the journal said debug had been on since ten past four the day before.
  56. ImranAnd the Build it section replays that, command by command.
  57. NadiaIt does. You log in and compare load with CPUs. You read top, check the disk, walk down with d u, and find the change in the journal and the config file. Then the fix: keep a small sample of the log as evidence, set the level back to info, stop the service, truncate the log, start it.
  58. ImranAnd then you check it held.
  59. NadiaStatus says running, the disk drops to about a quarter full, and a few minutes later the load falls. Then you write the ticket with every command you ran, so the next person can run them too.
  60. ImranFor my next review with the TechOps team, I'd ask three things. Who can log in to the boxes, and can we remove one person from all of them in one step? Is every Mangrove program run by systemd, as its own account, and enabled? And which alert fires before a disk fills up?
  61. NadiaAdd one more: when someone turns on debug logging, who turns it off, and when? That single question would have saved Ama's morning.
  62. NadiaNow a question for you, listener too. A box has four CPUs, load six, and top says the CPUs are seventy-eight percent idle. Where do you look first? Take a second.
  63. ImranThe CPUs are idle, so the load isn't CPU work. It's tasks waiting. I'd look at the disk.
  64. NadiaExactly. Check disk wait in top, how full the disks are, and what is writing heavily.
  65. ImranLet me sum it up. One: log in with your own key, never a shared password, and keep a session open while changing SSH. Two: permissions are owner, group, everyone else, first match wins, and seven seven seven is never the fix. Three: look before you restart, because a reboot wipes the evidence.
  66. NadiaGood list. One nuance on the third: when you do restart a service, use systemctl, not kill dash nine, so it gets the chance to save its work.
  67. ImranNext time?
  68. NadiaWe stop typing the same checks by hand every morning. Small, safe shell scripts that check the disk and clean up old logs for us.
Finished reading?Mark it complete to fill in its stop on your course line.

Use it at work

Runbook

Symptoms, first checks with commands, fixes and when to escalate, for one alert.

Open in the DevOps & TechOps Lab
Next stopShell scripting for daily jobs
Was this lesson helpful?
Questions and discussion

Loading the discussion…