By: Jahson Jno-Baptiste — a note to future me
If you’re rereading this, remember the point wasn’t to “do a bunch of commands.” It was to turn Linux fundamentals—files, shells, packages, users, permissions, services, storage, networking, and basic scripting—into muscle memory across two families of Linux. I built the lab to bounce between Ubuntu 24.04 (Debian lineage, apt) and Rocky 10 (RHEL lineage, dnf), because 010-160 asks you to recognize common ground and spot family differences without guessing. I took most screenshots on Rocky while verifying each task on both VMs. This is the path I followed, start to finish, with the checks that kept me honest.
I stood up two VMs in VMware with modest specs (2 vCPU, 7-8 GB RAM, ~40 GB disk). Ubuntu was my “Debian view,” Rocky the “RHEL view.” The decision that paid off later was treating them like cousins, not twins:
- Service names differ (
sshon Ubuntu vssshdon Rocky). - Logs differ (Ubuntu’s
/var/log/syslogvs Rocky’s/var/log/messages+ journal). - Package tools differ (
apt/apt-showvsdnf/info), including metadata language. - Networking tools rhyme but vary in config style (Ubuntu’s Netplan vs Rocky’s nmcli usage).
Before I touched anything, I verified reality with uname -a, cat /etc/os-release, and hostnamectl. That tiny identity check saved me from “why isn’t ssh started” moments that were really just service-name drift.
Muscle memory rule #1: verify what box you’re on, what kernel you’re on, and what init you’re under before changing anything.
Both VMs got immediate updates (apt update && apt upgrade -y on Ubuntu; dnf -y upgrade on Rocky). I installed open-vm-tools so copy/paste, time sync, and graceful shutdown worked. I added man-db / man-pages so help was local, and a minimal toolbelt (curl, wget, nano, less). This is boring on purpose: security begins with patching and productivity begins with man pages.
Proof points I captured: distro release banners (lsb_release -a on Ubuntu, /etc/redhat-release on Rocky) and the post-upgrade kernel from uname -r.
I practiced three help paths and when to use each:
man <cmd>when I need the canonical description and options.<cmd> --helpfor a quick syntax jog.type/whichwhen a name could be a shell builtin, alias, or a path (e.g.,type ls).
It sounds basic, but exam questions sneak in “how do you know what you’re calling?”. I turned that into a reflex.
Screenshot evidence: uname -a + a man ls snippet.
I drilled absolute vs relative paths (cd /etc vs cd -), visibility (ls -lah), and idempotent directory creation (mkdir -p ~/lab/a/b/c). I made copies that preserved permissions/times (cp -a), renamed with mv, and removed recursively intentionally with rm -r.
The aha wasn’t the commands—it was remembering that the shell expands globs (*.log) before the command sees them, and that quotes control expansion and spacing. I reinforced this with a quick tree -L 2 ~/lab after a few moves so I proved the structure, not just hoped.
Screenshot evidence: tree view of ~/lab and a simple find/glob example.
I practiced paging logs (less), slicing (head, tail, -F to follow), and filtering with grep -i. Then I chained them:
dmesg | grep -i usbto scan the kernel ring for hot-plug events.grep -RinE 'ERROR|WARN' /var/log 2>/dev/null | headto triage.
Two habits stuck: use a pager when the output can explode, and capture your assumptions in a short pipeline. The exam expects you to know these primitives; the job expects you to chain them without hesitation.
Screenshot evidence: your piping/grep capture.
Same workflow, two families:
- Ubuntu APT:
apt update,apt list --upgradable,apt install -y htop,apt show htop,apt remove,apt autoremove. - Rocky DNF:
dnf makecache,dnf check-update,dnf install -y htop,dnf info htop,dnf remove,dnf autoremove.
What I internalized: APT talks about indexes and candidates; DNF talks about repos and advisories. Different vocabulary, same intent. I took side-by-side screenshots of apt show htop vs dnf info htop to cement the mental mapping.
I created a practice user on both systems (adduser on Ubuntu vs useradd -m on Rocky), then granted admin: Ubuntu’s sudo group vs Rocky’s wheel. sudo -l confirmed the rights. The reflex I built was never to edit /etc/sudoers directly; always use visudo or a drop-in under /etc/sudoers.d/.
Screenshot evidence: id labuser on both.
I drilled symbolic and numeric mode (chmod 600 <=> u=rw,go=), ownership changes (chown user:group), sticky bit on shared dirs (1777), and ACLs for fine-grained exceptions:
setfacl -m u:labuser:r /etc/hostsplusgetfaclto verify.- Default ACLs on a directory so future files inherit sane rules.
The win here was remembering ACLs augment, not replace, POSIX perms—and that “it works for me” often fails for a peer until the default ACL is set at the directory root.
Screenshot evidence: getfacl /etc/hosts and ls -ld /srv/shared.
I toggled muscle memories:
- Process view:
ps aux | head,pgrep -a <name>,top(orhtopwhen installed). - systemd controls:
systemctl status ssh(Ubuntu) /status sshd(Rocky),enable --now, restarts, andis-enabled. - Logs:
journalctl -u ssh[ d] -n 50 --no-pager,journalctl -b | tail.
The exact service name mismatch is where people usually stumble. I made “check systemctl status before assuming” a rule. That habit saved me from chasing phantom SSH problems.
Screenshot evidence: systemctl status ssh on both flavors.
I observed before touching: lscpu, lsblk -f, df -hT, and du -h --max-depth=1 /var | sort -h.
For hands-on, I created a loopback disk (safe practice): dd an image, losetup it, mkfs.ext4, mount under /mnt/labdisk, and (temporarily) add an /etc/fstab entry. Then I validated with df -hT | grep labdisk and lsblk -f showing the loop device. That gave me real mkfs / mount / fstab reps without touching real disks.
Screenshot evidence: lsblk -f with loop device and a df -hT extract.
I later removed the
/etc/fstabline and detached the loop device to avoid surprises—cleanup is part of doing ops.
I affirmed the basics:
- Addresses & routes:
ip a,ip r. - Reachability:
ping -c 3 1.1.1.1, HTTP check withcurl -I https://example.com. - Name resolution:
getent hosts example.com(nsswitch path),host example.com(direct DNS).
This is where I caught the most “gotchas”: the default route lives on the NAT interface; the DNS tool differs by family (bind9-dnsutils vs bind-utils). I noted both in the README so I stop re-Googling them.
Screenshot evidence: ip a, ip r, and a resolver check.
I wrote a single-file backup script with safe defaults:
#!/usr/bin/env bash+set -euo pipefail.- Tar
/etcinto a timestamped archive under~/backups. - Printed the destination (
echo "Wrote $DEST") for clear evidence.
I ran it, then scheduled it with crontab -e (30 2 * * * ...). Finally, crontab -l and a log tail verified it ran. The point wasn’t the tarball; it was proving I can write, run, schedule, and validate a small automation without yak-shaving.
Screenshot evidence: script output + crontab -l.
I practiced two deliberate failures and clean recoveries:
- Bad DNS (edit
/etc/resolv.confto a bogus IP), then observeapt/dnffailures and repair by restoring DNS via Netplan/NM or DHCP. - Bad
/etc/fstabline, test withmount -a(expect error), then remove the typo and re-test until clean.
I intentionally skipped the firewall-lockout drill in this pass to keep the portfolio sequence tight; I’ve done it elsewhere and know how quickly it can derail the flow when you’re collecting screenshots.
Muscle memory rule #2: make one change, validate, and don’t stack unknowns. The “tiny break” approach makes your fixes tiny too.
Screenshot evidence: the mount -a error then a clean run; DNS failure snippet then a successful apt update/dnf makecache.
- Identify first, act second.
os-release+systemctl status+journalctltell you what box you’re really on and what it’s actually doing. - Debian vs RHEL is 80% overlap, 20% vocabulary.
apt showvsdnf info,sshvssshd,syslogvsmessages—know the mapping, not just the commands. - Permissions aren’t just chmod. ACLs and the sticky bit make shared spaces sane; default ACLs prevent “works for me” drift.
- fstab is powerful and fragile. Test with
mount -abefore you trust it to boot. - Pipes and pagers are force multipliers. Most “how do I find X” questions become a three-stage pipeline and a
less.
- I initially tailed the wrong log file on Rocky (went to
syslogmuscle memory). Fix: when in doubt, journalctl -u -b wins. - I forgot that Ubuntu’s SSH service is
ssh, notsshd. Fix: stop assuming;systemctl list-units --type=service | grep sshis cheap. - I wrote an
/etc/fstabentry by device node the first time. I rewrote it to use UUID, because device enumeration can change.
Tiny slips; useful corrections.
I organized screenshots in a reader-friendly order so a reviewer sees a story, not a dump:
- System identity (
rocky_system_identify,SYSTEM_IDENTIFY_ubuntu,ROCKY_RELEASE,UBUNTU_RELEASE). - VM configs (
rocky_vm_config,ubuntu_vm_config). - Navigation & files (
file_navigation,file_manipulation,tree_and_find,find). - Text + pipes (
man_ls,Piping,nano_and_script,script_output). - Packages (
package_manager). - Users & groups (
add_user). - Permissions & ACLs (
permissions_and_owners,ACLS,shared). - Processes/services/logs (
processes_services_and_logs,system_inspection). - Storage & mounts (
disks_and_mounts,fix_fstab). - Networking & DNS (
networking,name_resolution). - Cron (
crontab). - Break/fix DNS (
break_and_fix_dns_rocky).
Every image ties back to a command or outcome I can reproduce.
- Stronger storage reps: add a tiny LVM-on-loopback exercise so I practice
pvcreate/vgcreate/lvcreate+fstabwithout touching real disks. - Service health checks: follow a unit with
systemd-analyze blameandjournalctl -p warning -bto establish a habit of checking boot health. - Automation stub: bundle a small
make lab-checkthat reruns the evidence commands and writes to a datedlab-report.txt. That turns “I did it” into “I can prove it in 90 seconds.”
The best part of this lab wasn’t a particular command; it was the rhythm:
- Identify the system and state.
- Change one thing on purpose.
- Verify immediately with a relevant command.
- Capture evidence (screenshot or saved output).
- Clean up anything you won’t keep.
That rhythm is exactly what 010-160 (and real ops) reward. Future me: when you feel rusty, open the repo, rebuild the two VMs, and walk this path again. The knowledge is in your head; the confidence is in the checks.